なんか知らんがオリジナルのタグを練成できるらしい…
オリジナルタグの名前はダッシュ記号を含む名前である必要があるみたいで
んでオリジナルタグはジャヴァスクリプト使って練成しなきゃならんらしい
このオリジナルタグ、VB6だとUserControlみたいな感じぽい?
内部パーツ構成とかそんな感じぽい
スタイルも内部で独自に持つ感じで
shadowDOMという機能で実現してるらしい・・・?
テンプレ要素
繰り返し使うようなパターンを再利用するための仕組みぽい?
これもジャヴァスクリプトから操作して使うぽい
お試した
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>test</title>
<style>
ul { list-style: none; }
.softbutton {
border: none; background-color: rgb(224,224,224); border-radius: 3px;
cursor: pointer; font: unset; padding: 0px 0.2rem; color: darkgrey;
}
.softbutton:active { outline: 2px auto black; }
.softbutton:hover { color: black; }
.action { margin: 0px; margin-bottom: 0.5rem; }
.action > .softbutton { margin-right: 1rem; font-size: 0.8rem; }
.timeline .datetime { color: grey; font-size: 0.8em; }
.timeline ul > li { border-top: 1px solid lightgrey; }
</style>
</head>
<body>
<header>
<button>create custom element "post-template"</button>
<button>clone from template element with id="post-template"</button>
</header>
<main>
<section class="timeline">
<h5>timeline</h5>
<template id="post-template">
<!-- templateのCSSは独立してるらしく、htmlのCSSが効かない… -->
<li>
<div class="datetime"><time><slot name="datetime"></slot></time></div>
<p class="text"><slot name="text"></slot></p>
<slot name="images"><div>IMAGES HERE</div></slot>
<div class="action">
<button class="softbutton">reply</button>
<button class="softbutton">memo</button>
<button class="softbutton">edit</button>
<button class="softbutton">del</button>
</div>
<ul>
<slot name="replies"></slot>
</ul>
</li>
</template>
<template id="post-template-with-css">
<style>
ul { list-style: none; }
.softbutton {
border: none; background-color: rgb(224,224,224); border-radius: 3px;
cursor: pointer; font: unset; padding: 0px 0.2rem; color: darkgrey;
}
.softbutton:active { outline: 2px auto black; }
.softbutton:hover { color: black; }
.action { margin: 0px; margin-bottom: 0.5rem; }
.action > .softbutton { margin-right: 1rem; font-size: 0.8rem; }
.timeline .datetime { color: grey; font-size: 0.8em; }
.timeline ul > li { border-top: 1px solid lightgrey; }
/* templateの外の影響受けないぽいので.timelineやulのCSSセレクタが無効に… */
</style>
<li>
<div class="datetime"><time><slot name="datetime"></slot></time></div>
<p class="text"><slot name="text"></slot></p>
<slot name="images"><div>IMAGES HERE</div></slot>
<div class="action">
<button class="softbutton">reply</button>
<button class="softbutton">memo</button>
<button class="softbutton">edit</button>
<button class="softbutton">del</button>
</div>
<ul>
<slot name="replies"></slot>
</ul>
</li>
</template>
<ul>
<post-template>
<span slot="datetime">2020-08-02 21:05:01</span>
<span slot="text">ほげほげ~</span>
<span slot="images" style="font-size: 0.5em">post-template</span>
</post-template>
<post-template>
<span slot="datetime">2020-08-02 20:11:34</span>
<span slot="text">マジ~?</span>
<span slot="images" style="font-size: 0.5em">post-template</span>
<post-template slot="replies">
<span slot="datetime">2020-08-02 23:33:25</span>
<span slot="text">マジ!</span>
<span slot="images" style="font-size: 0.5em">post-template</span>
</post-template>
</post-template>
<post-template-with-css>
<span slot="datetime">2020-08-01 10:05:01</span>
<span slot="text">りんく!</span>
<span slot="images" style="font-size: 0.5em">post-template-with-css</span>
<post-template-with-css slot="replies">
<span slot="datetime">2020-08-02 03:22:00</span>
<span slot="text">りんく!りんく!</span>
<span slot="images" style="font-size: 0.5em">post-template-with-css</span>
</post-template-with-css>
</post-template-with-css>
<post-template>
<span slot="datetime">2020-08-01 03:33:31</span>
<span slot="text">あれれ~?</span>
<span slot="images" style="font-size: 0.5em">post-template</span>
</post-template>
</ul>
</section>
</main>
<script>
customElements.define('post-template',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('post-template');
let templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(templateContent.cloneNode(true));
}
});
customElements.define('post-template-with-css',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('post-template-with-css');
let templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(templateContent.cloneNode(true));
}
});
document.querySelector('header > button:first-child')
.addEventListener('click', () => {
const e = document.createElement('post-template');
// template内のcssが使われる…
const dt = e.appendChild(document.createElement('span'));
dt.textContent = '2020-08-02 23:59:59';
dt.slot = 'datetime';
const tx = e.appendChild(document.createElement('span'));
tx.textContent = 'This is Custom Element "post-template"';
tx.slot = 'text';
const span = e.appendChild(document.createElement('span'));
span.textContent = 'dummy'; // slot以外のノードの追加は出来ない…
alert(`[B] e: ${e}`); // OK (HTMLElement)
alert(`[B] li: ${e.querySelector('li')}`); // null
alert(`[B] .action: ${e.querySelector('.action')}`); // null
alert(`[B] *[slot="text"]: ${e.querySelector('*[slot="text"]')}`); // OK
const ul = document.querySelector('.timeline > ul');
ul.insertBefore(e, ul.firstChild);
alert(`[A] e: ${e}`); // OK (HTMLElement)
alert(`[A] li: ${e.querySelector('li')}`); // null
alert(`[A] .action: ${e.querySelector('.action')}`); // null
alert(`[A] *[slot="text"]: ${e.querySelector('*[slot="text"]')}`); // OK
});
document.querySelector('header > button:last-child')
.addEventListener('click', () => {
const template = document.getElementById('post-template');
const templateContent = template.content;
const clone = document.importNode(templateContent, true);
// ノードツリーの"構造"のコピーなのでcssがhtmlのものが適用される
clone.querySelector('time').textContent = '2020-08-02 11:57:57';
clone.querySelector('p').textContent = 'This is Clone from template element (id="post-template")';
const span = clone.appendChild(document.createElement('span'));
span.style.fontWeight = 'bold';
span.style.color = 'red';
span.textContent = 'dummy';
span.slot = 'images'; // slotタグは意味をなさない…
alert(`[B] clone: ${clone}`); // OK (DocumentFragment)
alert(`[B] li: ${clone.querySelector('li')}`); // OK
alert(`[B] .action: ${clone.querySelector('.action')}`); // OK
alert(`[B] *[slot="text"]: ${clone.querySelector('*[slot="text"]')}`); // null
const ul = document.querySelector('.timeline > ul');
ul.insertBefore(clone, ul.firstChild);
alert(`[A] clone: ${clone}`); // OK (DocumentFragment)
alert(`[A] li: ${clone.querySelector('li')}`); // null (move to html document (new owner))
alert(`[A] .action: ${clone.querySelector('.action')}`); // null (move to html document (new owner))
alert(`[A] *[slot="text"]: ${clone.querySelector('*[slot="text"]')}`); // null
});
</script>
</body>
</html>