Web-Components 定义,使用以及示例


1. 定义

web-componets 类似于vue以及react中组件定制,将一组ui以及公共逻辑抽取,并且封装成为一个公共组件。在页面可以随处调用

2. 实现web component的基本方法

a. 创建一个类或函数来指定web组件的功能

class Dialog extends HTMLElement {
	constructor() {
		super();
		const shadow = this.attachShadow({ mode: 'open' });
		const p = document.createElement('p');
		const text = this.getAttribute('dialog-text');
		p.textContent = text;
		shadow.appendChild(p);
	}
}

b. 用 customElements.define() 方法注册自定义的元素 ,并且指定component名称,以及创建的类。

customElements.define('dialog-element', Dialog);

c. 在页面中使用


	

d. 页面显示

4. 生命周期

  • connectedCallback
    • 当 custom element首次被插入文档DOM时,被调用
  • disconnectedCallback
    • 当 custom element从文档DOM中删除时,被调用
  • adoptedCallback
    • 当 custom element被移动到新的文档时,被调用
  • attributeChangedCallback
    • 当 custom element增加、删除、修改自身属性时,被调用
  • 生命周期使用实例
class Dialog extends HTMLElement {
    constructor() {
        super();
    }
    static get observedAttributes() {
        return ['dialog-text'];
    }

    connectedCallback() {
        console.log('dialog element added to page.');
    }

    disconnectedCallback() {
        console.log('dialog element removed from page.');
    }

    adoptedCallback() {
        console.log('dialog element moved to new page.');
    }

    attributeChangedCallback(name, oldValue, newValue) {
        console.log('dialog element attributes changed.');
    }
}

5. window.customElements属性

  • customElements.define
    • 定义:定义一个自定义元素
    • 语法:customElements.define(name, constructor, options);
    • 参数:
      • name:自定义元素名,所创建的元素名称的符合 DOMString 标准的字符串。注意,custom element 的名称不能是单个单词,且其中必须要有短横线
      • constructor: 自定义元素的构造类
      • options:控制元素如何定义 . 目前有一个选项支持
        • extends. 指定继承的已创建的元素. 被用于创建自定义元素.

示例

// customElements.define('dialog-element', Dialog);
// customElements.define('dialog-element', Dialog, { extends: 'div' });
// customElements.define('dialog-element', class extends HTMLElement {});
  • customElements.get
    • 定义:返回以前定义自定义元素的构造函数,如果获取不到,则返回undefined
    • 语法:const constructor = customElements.get(name);
    • 参数:
      • name: 自定义元素的名字

示例

const constructor = customElements.get('dialog-element');
console.log(constructor, `constructor`);
// class Dialog {}
  • customElements.whenDefined
    • 定义:当一个元素被定义时,返回一个promise,当获取到自定义元素时,立即resolve,当元素名称不是一个有效名称时,则立即执行rejecte
    • 语法:customElements.whenDefined(name)
    • 参数:
      • name: 自定义元素的名字
class Dialog extends HTMLElement {
    constructor() {
        super();

        const shadow = this.attachShadow({ mode: 'open' });

        const p = document.createElement('p');
        p.textContent = 'this is dialog element';

        shadow.appendChild(p);
    }
}
customElements.define('dialog-element', Dialog);

customElements.whenDefined('dialog-element').then(() => {
    console.log(`dialog-element is defined`);
});

customElements
    .whenDefined('aaa')
    .then(() => {
        console.log(`dialog-element is defined`);
    })
    .catch(err => {
        console.log(err, `err`);
// Failed to execute 'whenDefined' on 'CustomElementRegistry': "aaa" is not a valid custom element name
    });

6. custom elements类别

  • Autonomous custom elements
    • 说明:Autonomous custom elements 是独立的元素,可以直接在body内使用,例如,或者js创建document.createElement("task-list")
  • Customized built-in elements
    • 说明:Customized built-in elements 继承自基本的HTML元素。在创建时,必须指定继承的元素,也就是{ extends: 'div' },在body中使用
        ,js创建document.createElement('ul',{ is:'task-list' })

    7. 定义Autonomous custom elements组件

    • 使用shadow root外部样式影响不到组件
    class TaskList extends HTMLElement {
        constructor() {
            super();
            // 这里的this就是task-list元素
    
            // 创建一个shadow root
            const shadow = this.attachShadow({ mode: 'open' });
    
            // 通过getAttribute方法获取标签上的属性
            const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
    
            // 创建一个ul元素
            const ul = document.createElement('ul');
            ul.classList.add('task-list');
    
            // 循环创建li元素
            dataList.forEach(item => {
                const li = document.createElement('li');
                li.classList.add('task-item');
                li.textContent = item;
                li.addEventListener('click', this.showItemContent.bind(this, li));
                ul.appendChild(li);
            });
    
            // 创建样式
            const style = document.createElement('style');
            style.textContent = this.defineStyle();
    
            // 将样式添加至shadow 根节点
            shadow.appendChild(style);
    
            // 将ul添加至shadow 根节点
            shadow.appendChild(ul);
        }
        /**
         * 定义组件样式,外部style无法影响组件样式
         */
        defineStyle() {
            return `
                .task-list{
                    list-style: none;
                }
            `;
        }
    
        showItemContent(ele) {
            console.log(ele.textContent, `ele.textContent`);
        }
    }
    // 定义task-list组件
    customElements.define('task-list', TaskList);
    

    页面显示

    • 不使用shadow root 外部样式可以影响组件
    
    
    class TaskList extends HTMLElement {
        constructor() {
            super();
            // 这里的this就是task-list元素
    
            // 通过getAttribute方法获取标签上的属性
            const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
    
            // 创建一个ul元素
            const ul = document.createElement('ul');
            ul.classList.add('task-list');
    
            // 循环创建li元素
            dataList.forEach(item => {
                const li = document.createElement('li');
                li.classList.add('task-item');
                li.textContent = item;
                li.addEventListener('click', this.showItemContent.bind(this, li));
                ul.appendChild(li);
            });
    
            // 将ul添加至根节点
            this.appendChild(ul);
        }
    
        showItemContent(ele) {
            console.log(ele.textContent, `ele.textContent`);
        }
    }
    // 定义task-list组件
    customElements.define('task-list', TaskList);
    

    页面展示

    8. 定义Customized built-in elements组件

      
      
      class TaskList extends HTMLUListElement {
          constructor() {
              super();
              // 这里的this就是task-list元素
              this.classList.add('task-list');
              // 通过getAttribute方法获取标签上的属性
              const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
      
              // 循环创建li元素
              dataList.forEach(item => {
                  const li = document.createElement('li');
                  li.classList.add('task-item');
                  li.textContent = item;
                  this.appendChild(li);
              });
          }
      }
      
      // 定义task list组件,必须定义{ extends: 'ul' },否则会报错
      // Illegal constructor: autonomous custom elements must extend HTMLElement
      customElements.define('task-list', TaskList, { extends: 'ul' });
      

      页面展示

      9. 定义组件的方式

      • template方式
      
      
      
      
      
      customElements.define(
          'task-list',
          class extends HTMLElement {
              constructor() {
                  super();
                  let template = document.getElementById('task-list');
                  let templateContent = template.content;
                  // 使用cloneNode方式将templateContent添加到当前元素中
                  this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
              }
          }
      );
      

      页面展示

      10. 插槽的使用

      
      
      
      
          
          

      this is slot content

      customElements.define(
          'task-list',
          class extends HTMLElement {
              constructor() {
                  super();
                  let template = document.getElementById('task-list');
                  let templateContent = template.content;
                  // 使用cloneNode方式将templateContent添加到当前元素中
                  this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
              }
          }
      );
      

      页面展示

      11. webcomponets示例之notify组件

      
      
          
              
              
              
              webcomponets示例之notify组件