Web Component #4 - template模板和Slot插槽
Slot
slot插槽,占位. 参考vue
mdn: https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/slot
参考vue:https://cn.vuejs.org/guide/components/slots.html
下面示例,自定名为"my-card"自定义组件,可以自定义标题和内容.
<body>
<div id="app">
<my-card></my-card>
<my-card>自定义内容</my-card>
<my-card>
<span slot="title">自定义标题</span>
自定义内容
</my-card>
</div>
<!-- 组件模板 -->
<template id="card-template">
<style>
:host{
display: block;
border: 1px solid #ccc;
margin: 10px;
}
.title,.content{
margin: 0;
padding: 5px;
}
.title{
background-color: #ccc;
}
</style>
<div >
<!-- 标题插槽 -->
<header class="title"><slot name="title">默认标题</slot></header>
<!-- 内容插槽 -->
<div class="content">
<slot>默认内容</slot>
</div>
</div>
</template>
<script>
customElements.define(
'my-card',
class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template=document.querySelector('#card-template');
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
)
</script>
</body>
结构
与slot关联的元素为slotable Element
组件中定义slot
- 匿名slot
<slot>默认内容</slot>
有名slot
<slot name="title"></slot>
默认值
<slot name="title">默认标题</slot>
共用多个
<slot name="title">默认标题1</slot> <slot name="title">默认标题2</slot>
注意: 如果组件中没有定义任何slot或匿名slot,插入到组件的内容将不显示.
<tempalte>
</template>
<my-card>
<p>不显示</p>
</my-card>
可以利用这个特性,临时存储一下内容,然后通过修改slot来显示.
slot传参
可以传任意标签内容
匿名slot
<my-card> <p>任意内容</p> </my-card>
具名slot
<my-card> <h3 slot="title">标题</h3> <p>任意内容</p> </my-card>
纯文本内容
<my-card> <slot slot="title">标题</slot> <p>任意内容</p> </my-card>
同时传多个
<my-card> <h3 slot="title">标题1</h3> <h4 slot="title">标题2</h4> <p>任意内容</p> </my-card>
样式
::slotted()
选择器,slot中有内容. 用于区分已插入和未插入.
注意: ::slotted(*)
不能选择纯文本内容,最好用标签包起来.
<template>
<style>
::slotted(*){
color:red;
}
::slotted(h2){
color:blue;
}
</style>
<header><h2 name="title">默认标题</h2></header>
</template>
组件中获取slot内容
通过assignedElements
获取分配给slot内容.
<script>
customElements.define(
'my-card',
class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template=document.querySelector('#card-template');
this.shadowRoot.appendChild(template.content.cloneNode(true));
const slotElements = this.shadowRoot.querySelectorAll('slot');
for(let slotElement of slotElements){
const assignedElements = slotElement.assignedElements({ flatten: true });
// 可以有多个
console.log(assignedElements[0]?.innerHTML);
}
}
}
)
</script>
事件
slotchange
事件可以监听slot的内容变化.
注意: slotchange 事件不能取消. 只能监听slot的添加删除,属性的变化.
<div id="app">
<my-card id="my-card">
xxx
</my-card>
<button id="btn">添加内容</button>
</div>
<!-- 组件模板 -->
<template id="card-template">
<style>
:host{
display: block;
border: 1px solid #ccc;
margin: 10px;
}
.title,.content{
margin: 0;
padding: 5px;
}
.title{
background-color: #ccc;
}
::slotted(*){
color:red;
}
::slotted(h2){
color:blue;
}
</style>
<div >
<!-- 内容插槽 -->
<div class="content">
<slot>默认内容</slot>
</div>
</div>
</template>
<script>
customElements.define(
'my-card',
class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template=document.querySelector('#card-template');
this.shadowRoot.appendChild(template.content.cloneNode(true));
const slot = this.shadowRoot.querySelector('slot');
// 事件
slot.addEventListener("slotchange",function(e){
console.log(this.assignedNodes());
})
}
}
)
</script>
<script>
const btn=document.querySelector('#btn');
const card=document.querySelector('#my-card');
// 添加内容
btn.addEventListener('click',function(){
card.innerHTML="";
const p=document.createElement("p");
p.innerText="内容"+Math.random();
card.appendChild(p);
})
</script>
</body>
组件中的slotable Element变化,都会触发slotchange事件.
btn.addEventListener('click',function(){
// 1.添加slot属性
// card.querySelector("p").setAttribute("slot","content");
// 2.修改slot
// card.querySelector("[slot='title']").setAttribute("slot","content");
// 3. 删除slot
//card.querySelector("[slot='title']").removeAttribute("slot");
// 4. 删除原元素
// card.querySelector("[slot='title']").remove();
// 5. 设置innertHTML
// card.innerHTML="";
// 6. 删除slot本身
// card.shadowRoot.querySelector("slot[name='title']").remove();
})
动态创建slot
// 动态创建slot
slot=document.createElement('slot');
slot.addEventListener("slotchange",function(e){
console.log(this.assignedNodes());
})
card.shadowRoot.appendChild(slot);
原作者:阿金
本文地址:https://hi-arkin.com/archives/web-components-4.html