本文共 6303 字,大约阅读时间需要 21 分钟。
优点:原生组件,不需要框架,性能好代码少。
缺点:兼容性问题组件化好处: 高内聚、可重用、可组合WebComponent
<template>
和 <slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。组件的名字必须以中划线分割,避免与native标签冲突
折叠分栏组件
1、组件使用
nodejs welcome react welcome vue welcome
2、定义组件模板
3、 引入组件
4、 注册组件
window.customElements.define('zf-collapse',Collapse);
window.customElements.define('zf-collapse-item',CollapseItem);
用于注册组件
import Collapse from './collapse.js';import CollapseItem from './collapse-item.js';window.customElements.define('zf-collapse',Collapse);window.customElements.define('zf-collapse-item',CollapseItem);// 设置组件默认显示的状态 let defaultActive = ['1','2']; // name:1 name:2 默认展开 3 应该隐藏document.querySelector('zf-collapse').setAttribute('active',JSON.stringify(defaultActive));// 每个item需要获取到defaultActive 和自己的name属性比较,如果在里面就显示,不在里面就隐藏document.querySelector('zf-collapse').addEventListener('changeName',(e)=>{ let {isShow,name} = e.detail; if(isShow){ let index = defaultActive.indexOf(name); defaultActive.splice(index,1); }else{ defaultActive.push(name); } document.querySelector('zf-collapse').setAttribute('active',JSON.stringify(defaultActive));});// shadowDOM 完全隔离// 组件间的通信 属性,事件// customEvent -> webcomponent 兼容性差,没有自动更新机制
defaultActive是初始展开的name
一开始把defaultActive设置在zf-collapse dom上的active属性 后续传递给子组件使用
监听changeName事件 再改变active属性
继承HTMLElement
1)先调用this.attachShadow({ mode: 'open' })激活shadowDOM
2)拿到组件模板dom 拷贝一份
let cloneTemplate = tmpl.content.cloneNode(true);
3) 定义style style.textContent ...
4) dom和 style 放在shadow
shadow.appendChild(style);
shadow.appendChild(cloneTemplate);
5) 监控slot变化 插槽有值时 记录this.slotList (子组件记录)
执行 render是为了给子组件 改变active
slot.addEventListener('slotchange', (e) => {
this.slotList = e.target.assignedElements();
this.render();
})
observedAttributes 监听active属性变化
attributeChangedCallback 属性变化回调 重新赋值 this.activeList, 执行this.render
collapse.js主要记录active属性变化 并传给子组件
class Collapse extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: 'open' }); const tmpl = document.getElementById('collapse_tmpl'); let cloneTemplate = tmpl.content.cloneNode(true); let style = document.createElement('style'); // :host 代表的是影子的根元素 style.textContent = ` :host{ display:flex; border:3px solid #ebebeb; border-radius:5px; width:100%; } .zf-collapse{ width:100%; } ` shadow.appendChild(style); shadow.appendChild(cloneTemplate); let slot = shadow.querySelector('slot'); // 监控slot变化 slot.addEventListener('slotchange', (e) => { this.slotList = e.target.assignedElements(); this.render(); }) } static get observedAttributes() { // 监控属性的变化 return ['active'] } // update attributeChangedCallback(key, oldVal, newVal) { if (key == 'active') { this.activeList = JSON.parse(newVal); this.render(); } } render() { if (this.slotList && this.activeList) { [...this.slotList].forEach(child => { child.setAttribute('active', JSON.stringify(this.activeList)) }); } } // connectedCallback(){ // console.log('插入到dom时执行的回调') // } // disconnectedCallback(){ // console.log('移除到dom时执行的回调') // } // adoptedCallback(){ // console.log('将组件移动到iframe 会执行') // }}export default Collapse
6、CollapseItem组件定义
class CollapseItem extends HTMLElement { constructor() { super(); let shadow = this.attachShadow({ mode: 'open' }); let tmpl = document.getElementById('collapse_item_tmpl'); let cloneTemplate = tmpl.content.cloneNode(true); let style = document.createElement('style'); this.isShow = true; // 标识自己是否需要显示 style.textContent = ` :host{ width:100%; } .title{ background:#f1f1f1; line-height:35px; height:35px; } .content{ font-size:14px; } ` shadow.appendChild(style) shadow.appendChild(cloneTemplate); this.titleEle = shadow.querySelector('.title'); this.titleEle.addEventListener('click',()=>{ // 如果将结果传递给父亲 组件通信? document.querySelector('zf-collapse').dispatchEvent(new CustomEvent('changeName',{ detail:{ name:this.getAttribute('name'), isShow:this.isShow } })) }) } static get observedAttributes() { // 监控属性的变化 return ['active', 'title', 'name'] } // update attributeChangedCallback(key, oldVal, newVal) { switch (key) { case 'active': this.activeList = JSON.parse(newVal); // 子组件接受父组件的数据 break; case 'title': this.titleEle.innerHTML = newVal; // 接受到title属性 作为dom的title break; case 'name': this.name = newVal break; } let name = this.name; if (this.activeList && name) { this.isShow = this.activeList.includes(name); this.shadowRoot.querySelector('.content').style.display = this.isShow ? 'block' : 'none' } }}export default CollapseItem
title dom 定义click事件, 向zf-collapse dom元素触发 自定义事件changeName, 传 name isShow,
observedAttributes 观察3个属性变化
attributeChangedCallback 属性变化后的回调
this.activeList: 父组件的传的参数
title是该组件的title
name是该组件name
如果name在this.activeList里面 就是展示 显示样式block 即可。
顶层组件传 activeList 子组件判断 展示就行了
转载地址:http://qkm.baihongyu.com/