本文共 6303 字,大约阅读时间需要 21 分钟。
优点:原生组件,不需要框架,性能好代码少。
缺点:兼容性问题组件化好处: 高内聚、可重用、可组合WebComponent
<template> 和 <slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。组件的名字必须以中划线分割,避免与native标签冲突

折叠分栏组件

1、组件使用
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/