美文网首页
了解 Web Components

了解 Web Components

作者: DoNow | 来源:发表于2020-10-19 21:38 被阅读0次

简介

Web Components 标准非常重要的一个特性是,它使开发者能够将HTML页面的功能封装为 custom elements(自定义标签)。

技术组成

1. Custome Elements:自定义元素,通过 JavaScript API 来创建。

两种类型

Autonomous custom elements 是独立的元素,它不继承其他内建的HTML元素。你可以直接把它们写成HTML标签的形式,来在页面上使用。例如 <popup-info>,或者是document.createElement("popup-info")这样。

Customized built-in elements 继承自基本的HTML元素。在创建时,你必须指定所需扩展的元素(正如上面例子所示),使用时,需要先写出基本的元素标签,并通过 is 属性指定custom element的名称。例如<p is="word-count">, 或者 document.createElement("p", { is: "word-count" })

MDN官方介绍

官方例子

main.js

// Create a class for the element
class Square extends HTMLElement {
  // Specify observed attributes so that
  // attributeChangedCallback will work
  static get observedAttributes() {
    return ['c', 'l'];
  }

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

    const shadow = this.attachShadow({mode: 'open'});
    console.log('shaow-->', shadow);

    const div = document.createElement('div');
    const style = document.createElement('style');
    shadow.appendChild(style);
    shadow.appendChild(div);
  }

  connectedCallback() {
    console.log('Custom square element added to page.');
    updateStyle(this);
  }

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

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

  attributeChangedCallback(name, oldValue, newValue) {
    console.log('Custom square element attributes changed.');
    updateStyle(this);
  }
}

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

function updateStyle(elem) {
  console.log('elem-->', elem);
  const shadow = elem.shadowRoot;
  shadow.querySelector('style').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;
};

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Life cycle callbacks test</title>
    <style>
      custom-square {
        margin: 20px;
      }
    </style>
    <script defer src="main.js"></script>
  </head>
  <body>
    <h1>Life cycle callbacks test</h1>

    <div>
      <button class="add">Add custom-square to DOM</button>
      <button class="update">Update attributes</button>
      <button class="remove">Remove custom-square from DOM</button>
    </div>

  </body>
</html>

运行结果

兼容性:Firefox、Chrome和Opera默认就支持 custom elements。Safari目前只支持 autonomous custom elements(自主自定义标签),而 Edge也正在积极实现中。

2. Shadow DOM:隔离 CSS 和 JavaScript,跟操作常规Dom类似。

<video>元素就是使用shadow dom实现一系列的按钮和其他控制器。可以使用 Element.attachShadow({ mode: 'open' }) 方法来将一个 shadow root 附加到任何一个元素上。open表示可以通过页面内的 JavaScript 方法来获取 Shadow DOM{ mode: 'closed' }表示 Shadow DOM 是封闭的,不允许外部访问。

使用方式.

MDN官方介绍

image.png

相关术语

Shadow host:一个常规 DOM节点,Shadow DOM 会被附加到这个节点上。
Shadow tree:Shadow DOM内部的DOM树。
Shadow boundary:Shadow DOM结束的地方,也是常规 DOM开始的地方。
Shadow root: Shadow tree的根节点。

兼容性:Firefox(从版本 63 开始),Chrome,Opera 和 Safari 默认支持 Shadow DOM。

例子

main.js

// Create a class for the element
class PopUpInfo extends HTMLElement {
  constructor() {
    // Always call super first in constructor
    super();

    // Create a shadow root
    const shadow = this.attachShadow({mode: 'open'});

    // Create spans
    const wrapper = document.createElement('span');
    wrapper.setAttribute('class', 'wrapper');

    const icon = document.createElement('span');
    icon.setAttribute('class', 'icon');
    icon.setAttribute('tabindex', 0);

    const info = document.createElement('span');
    info.setAttribute('class', 'info');

    // Take attribute content and put it inside the info span
    const text = this.getAttribute('data-text');
    info.textContent = text;

    // Insert icon
    let imgUrl;
    if(this.hasAttribute('img')) {
      imgUrl = this.getAttribute('img');
    } else {
      imgUrl = 'img/default.png';
    }

    const img = document.createElement('img');
    img.src = imgUrl;
    icon.appendChild(img);

    // Apply external styles to the shadow dom
    const linkElem = document.createElement('link');
    linkElem.setAttribute('rel', 'stylesheet');
    linkElem.setAttribute('href', 'style.css');

    // Attach the created elements to the shadow dom
    shadow.appendChild(linkElem);
    shadow.appendChild(wrapper);
    wrapper.appendChild(icon);
    wrapper.appendChild(info);
  }
}

// Define the new element
customElements.define('popup-info', PopUpInfo);

style.css

.wrapper {
  position: relative;
}

.info {
  font-size: 0.8rem;
  width: 200px;
  display: inline-block;
  border: 1px solid black;
  padding: 10px;
  background: white;
  border-radius: 10px;
  opacity: 0;
  transition: 0.6s all;
  position: absolute;
  bottom: 20px;
  left: 10px;
  z-index: 3;
}

img {
  width: 1.2rem;
}

.icon:hover + .info, .icon:focus + .info {
  opacity: 1;
}

index.html

 <h1>Pop-up info widget - web components</h1>

    <form>
      <div>
        <label for="cvc">Enter your CVC <popup-info img="img/alt.png" data-text="Your card validation code (CVC) is an extra security feature — it is the last 3 or 4 numbers on the back of your card."></popup-info></label>
        <input type="text" id="cvc">
      </div>
    </form>

运行结果

shadow dom VS iframe

shadow dom

  1. 渲染得更快,占用内存更少;
  2. 具备较好的灵活性;
  3. 隔离样式;

iframe
MDN-iframe

  1. 增加内存和其他计算资源,因为每个浏览上下文都拥有完整的文档环境;
  2. 隔离样式
  3. 需要动态设置高度,否则内容超出高度,会显示滚动条;
  4. 无法操作内嵌表单
  5. 移动端兼容性差
  6. 需要服务器辅助配置,否则会出现跨域

dom嵌入页面提高性能的兼容性写法

let content = `
  <style>
    body { /* for fallback iframe */
      margin: 0;
    }
    p { 
      border: 1px solid #ccc;
      padding: 1rem;
      color: red;
      font-family: sans-serif;
    }
  </style>

  <p>Element with Shadow DOM</p>
`;

let el = document.querySelector('.my-element');

if (document.body.attachShadow) {
  let shadow = el.attachShadow({ mode: 'open' }); // Allows JS access inside
  shadow.innerHTML = content;
  
} else {
  
  let newiframe = document.createElement('iframe');
  'srcdoc' in newiframe ?
    newiframe.srcdoc = content :
    newiframe.src = 'data:text/html;charset=UTF-8,' + content;
  
  let parent = el.parentNode;
  parent.replaceChild(newiframe, el);

}

3. Templates and Slots:用户在HTML中定义的模板,只有调用的时候才会被渲染。

可以通过使用 <template><slot> 元素创建一个可以用来灵活填充 Web组件的 shadow DOM 的模板。请查看例子

template例子
自定义my-paragraph标签,实现内容是,创建一个 shadow dom,将模板的内容拷贝进 shadow 根结点上。

<template id="my-paragraph">
  <style>
    p {
      color: white;
      background-color: #666;
      padding: 5px;
    }
  </style>
  <p>My paragraph</p>
</template>
<my-paragraph></my-paragraph>
customElements.define('my-paragraph',
  class extends HTMLElement {
    constructor() {
      super();
      let template = document.getElementById('my-paragraph');
      let templateContent = template.content;

      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(templateContent.cloneNode(true));
  }
})

slot插槽例子

customElements.define('person-details',
  class extends HTMLElement {
    constructor() {
      super();

      const template = document.getElementById('person-template');
      const templateContent = template.content;

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

      const style = document.createElement('style');
      style.textContent = `
        div { padding: 10px; border: 1px solid gray; width: 200px; margin: 10px; }
        h2 { margin: 0 0 10px; }
        ul { margin: 0; }
        p { margin: 10px 0; }
        ::slotted(*) { color: gray; font-family: sans-serif; }
      `;

      shadowRoot.appendChild(style);
      shadowRoot.appendChild(templateContent.cloneNode(true));
  }
});
<template id="person-template">
  <div>
    <h2>Personal ID Card</h2>
    <slot name="person-name">NAME MISSING</slot>
    <ul>
      <li><slot name="person-age">AGE MISSING</slot></li>
      <li><slot name="person-occupation">OCCUPATION MISSING</slot></li>
    </ul>
  </div>
</template>

    <person-details>
      <p slot="person-name">Morgan Stanley</p>
      <span slot="person-age">36</span>
      <span slot="person-occupation">Accountant</span>
    </person-details>

    <person-details>
      <p slot="person-name">Dr. Shazaam</p>
      <span slot="person-age">Immortal</span>
      <span slot="person-occupation">Superhero</span>
    </person-details>

    <person-details>
      <p slot="person-name">Boris</p>
      <span slot="age">27</span>
      <span slot="i-am-awesome">Time traveller</span>
    </person-details>
image.png

相关文章

  • 未来学习规划

    了解Web Components开发;zh-Web_Components、en-Web_Components 了解...

  • 了解 Web Components

    Web Components 首先来了解下 Web Components 的基本概念, Web Component...

  • 了解 Web Components

    简介 Web Components 标准非常重要的一个特性是,它使开发者能够将HTML页面的功能封装为 custo...

  • web components

    web components:一种原生的写组件的方式。下面将主要介绍四个概念:custom element、sha...

  • Web Components

    作用: Web组件化,可复用UI模块。 标准: Web Components不是单一的规范,而是一系列的技术组成,...

  • web components

    首先来看浏览器源生的web components demohttps://www.webcomponents.or...

  • Web Components

    一、组件化开发 1、组件化开发的优势 管理和使用非常容易,加载或卸载组件,只要添加或删除一行代码就可以了 组件非常...

  • Web Components

    定义 浏览器原生支持的一套组件封装技术。这里有两个关键字: 组件技术 浏览器原生 组件化一直是前端完善的方向,从早...

  • Web Components

    Web Components允许创建可重用的定制元素,并且在web应用中使用它们。 HTML Templates ...

  • Web Components

    组件化是前端工程化重要的一环,UI 和 交互(或逻辑)的复用极大的提高开发效率以及减少代码冗余。 目前开源的组件库...

网友评论

      本文标题:了解 Web Components

      本文链接:https://www.haomeiwen.com/subject/uqmlmktx.html