博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WebComponent小demo
阅读量:54 次
发布时间:2019-02-25

本文共 6303 字,大约阅读时间需要 21 分钟。

未来组件化开发趋势WebComponent

 

优点:原生组件,不需要框架,性能好代码少。

缺点:兼容性问题

组件化好处: 高内聚、可重用、可组合WebComponent

一、 核心三项技术

  • Custom elements:一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们
  • Shadow DOM:一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
  • HTML templates: <template> 和 <slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

 

组件的名字必须以中划线分割,避免与native标签冲突

 

  • shadow DOM 可以实现真正的隔离机制 

 

 

 

二、实现Collapse 折叠面板组件

 

折叠分栏组件

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属性

 

5、collapse.js 组件定义

继承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/

你可能感兴趣的文章