Web Components 初识

Web components可以将html标签结构、css样式和行为隐藏起来,并从页面上的其他代码中分离开来,这样不同的功能不会混在一起,封装为 custom elements(自定义标签),并且可以运用template重复html结构片段,你用slot配合创建弹性模板

1.custom elements (自主自定义标签----创建一个标签)

基本用法: customElements.define(name, constructor[, options]);

  • name --一个DOMString, 用于表示所创建的元素的名称。注意,custom element 的名称中必须要有短横线
  • constructor 一个类对象,用于定义元素的行为
  • options 可选参数 包含 extends属性的配置对象,指定了所创建的元素继承自哪个内置元素,可以继承任何内置元素

栗子

customElements.define('word-count', WordCount, { extends: 'p' }); // 这个元素叫做 `word-count`,它的类对象是 `WordCount`, 继承自 

元素 class WordCount extends HTMLParagraphElement { constructor() { // 必须首先调用 super方法 super(); // 元素的功能代码写在这里 ... } }

共有两种 custom elements:
  1. Autonomous custom elements 是独立的元素,它不继承其他内建的HTML元素。你可以直接把它们写成HTML标签的形式,来在页面上使用。例如 ,或者是document.createElement("popup-info")这样
class PopUpInfo extends HTMLElement {
  constructor() {
    // 必须首先调用 super方法 
    super(); 

    // 元素的功能代码写在这里

    ...
  }
}
customElements.define('popup-info', PopUpInfo);

// 页面上

  1. Customized built-in elements 继承自基本的HTML元素。在创建时,你必须指定所需扩展的元素(正如上面例子所示),使用时,需要先写出基本的元素标签,并通过 is 属性指定custom element的名称。例如

    , 或者 document.createElement("p", { is: "word-count" })

class ExpandingList extends HTMLUListElement {   // 这里的真正不同点在于元素继承的是HTMLUListElement接口,而不是HTMLElement

  constructor() {
    // 必须首先调用 super方法 
    super();

    // 元素的功能代码写在这里

    ...
  }
}
customElements.define('expanding-list', ExpandingList, { extends: "ul" });


// 页面上
    ...

参考: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_custom_elements

2. shadow DOM (Shadow DOM允许将隐藏的DOM树添加到常规的DOM树中)

Web Components 初识_第1张图片
image
  • 需要了解的 Shadow DOM相关技术:
  • Shadow host: 一个常规 DOM节点,Shadow DOM会被添加到这个节点上
  • Shadow tree:Shadow DOM内部的DOM树。
  • Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
  • Shadow root: Shadow tree的根节点。

基本用法: element.attachShadow({mode: 'open' | 'closed'});

  • mode 接受open 或者 closed;
  • open 表示你可以通过页面内的 JavaScript 方法来获取 Shadow DOM
  • 如果你将一个 Shadow root 添加到一个 Custom element 上,并且将 mode设置为closed,那么就不可以在外部获取 Shadow DOM了——myCustomElem.shadowRoot 将会返回 null。浏览器中的某些内置元素就是这样的,例如

简单的栗子:

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

var wrapper = document.createElement('span');
wrapper.setAttribute('class','wrapper');

shadow.appendChild(wrapper);

复杂点的栗子:(与custom elements配合使用)

// main.js
// Create a class for the element
class Square extends HTMLElement {
  // Specify observed attributes so that
  // attributeChangedCallback will work
// 触发 attributeChangedCallback()回调函数,必须监听这个属性
// 通过定义observedAttributes() get函数来实现,observedAttributes()函数体内包含一个 return语句,返回一个数组,包含了需要监听的属性名称
  static get observedAttributes() {
    return ['c', 'l'];
  }

  constructor() {
    // Always call super first in constructor
    super();

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

    const div = document.createElement('div');
    const style = document.createElement('style');
    shadow.appendChild(style);
    shadow.appendChild(div);
  }
 // 当 custom element首次被插入文档DOM时,被调用。
  connectedCallback() {
    console.log('Custom square element added to page.');
    updateStyle(this);
  }
// 当 custom element从文档DOM中删除时,被调用。
  disconnectedCallback() {
    console.log('Custom square element removed from page.');
  }
// 当 custom element被移动到新的文档时,被调用。
  adoptedCallback() {
    console.log('Custom square element moved to new page.');
  }
// 当 custom element增加、删除、修改自身属性时,被调用。
  attributeChangedCallback(name, oldValue, newValue) {
    console.log('Custom square element attributes changed.');
    updateStyle(this);
  }
}

customElements.define('custom-square', Square);

function updateStyle(elem) {
  const shadow = elem.shadowRoot;
  const childNodes = Array.from(shadow.childNodes);
  
  childNodes.forEach(childNode => {
    if (childNode.nodeName === 'STYLE') {
      childNode.textContent = `
        div {
          width: ${elem.getAttribute('l')}px;
          height: ${elem.getAttribute('l')}px;
          background-color: ${elem.getAttribute('c')};
        }
      `;
    }
  });
}

const add = document.querySelector('.add');
const update = document.querySelector('.update');
const remove = document.querySelector('.remove');
let square;

update.disabled = true;
remove.disabled = true;

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

add.onclick = function() {
  // Create a custom square element
  square = document.createElement('custom-square');
  square.setAttribute('l', '100');
  square.setAttribute('c', 'red');
  document.body.appendChild(square);

  update.disabled = false;
  remove.disabled = false;
  add.disabled = true;
};

update.onclick = function() {
  // Randomly update square's attributes
  square.setAttribute('l', random(50, 200));
  square.setAttribute('c', `rgb(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)})`);
};

remove.onclick = function() {
  // Remove the square
  document.body.removeChild(square);

  update.disabled = true;
  remove.disabled = true;
  add.disabled = false;
};


  
    
    Life cycle callbacks test
    
    
  
  
    

Life cycle callbacks test

    *由shadow DOM里面添加的样式不会影响到外面,而且外面也不会影响里面。

    参考: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_shadow_DOM

    3. template slots

    • template标签里的代码不会展现在页面中,知道js获取它的引用,然后添加到dom中,才会展示。
    // html
    
    
    // js
    let template = document.getElementById('my-paragraph');
    let templateContent = template.content;
    document.body.appendChild(templateContent);
    
    • 和web组件一起使用template
    customElements.define('my-paragraph',
      class extends HTMLElement {
        constructor() {
          super();
          let template = document.getElementById('my-paragraph');
          let templateContent = template.content;
          
        //Node.cloneNode() 方法添加了模板(template) 的拷贝到阴影(shadow) 的根结点上.
          const shadowRoot = this.attachShadow({mode: 'open'})
            .appendChild(templateContent.cloneNode(true));  
    
      }
    })
    
    
    
    
    

    slot增加灵活度

    • 我们将模板(tempalte) 的 p 标签改成下面这样

    My default text

    
      Let's have some different text!
    
    

    或者

    
      
    • Let's have some different text!
    • In a list!
    • 这样就可以灵活的添加内容到模板中了。

    栗子:

    
    
    
    
      
        slot example
        
      
      
        
    
        
          slot
          A placeholder inside a web
            component that users can fill with their own markup,
            with the effect of composing different DOM trees
            together.
          
    name
    The name of the slot.
    template A mechanism for holding client- side content that is not to be rendered when a page is loaded but may subsequently be instantiated during runtime using JavaScript.
    • template外面的样式不会影响到里面的样式,里面也不会影响外面。

    你可能感兴趣的:(Web Components 初识)