ribbon image search rewind fast-forward speech-bubble pie-graph star

Web Components

React.js, Vue.js 的流行不是偶然,现代的工程化体系中离不开组件化的体系。我们充分享受了组件化带来工程效率的提升以及社区的优势。

Web Component是 是一些 W3C 官方定义的一些技术的合集表现,主要是下面三个内容:

自定义元素

自定元元素,也就是在 Html 中实实在在的标签,就像 DIV, SPANARTICLE 一样,我们可以写在我们 HTML 代码中一样。不过他们都是由短线连接表示的。诸如下面这些都可以

  • <new-slider>
  • <base-player>
  • <photo-dialog>

自定义元素包含自己的语义,行为以及标签内容,并且可以在不同的框架和浏览器使用。

一个简单的元素代码;

class MyComponent extends HTMLElement {  
  connectedCallback() {
    this.innerHTML = `<h1>Hello world</h1>`;
  }
}

customElements.define('my-component', MyComponent);  

上面代码我们可以看出, 我们定义了一个 <my-component> , 它仅仅是一个组件然后显示一段文字,但是它却可以通过直接编写 HTML 的形式并且渲染到浏览器中。

这些自定义的元素并不依赖于第三方框架,而且这些组建可以完美的在流行的框架(React,Angular)中得到支持。

Shadow DOM

Shadow DOM 实际上算是对 DOM 的一种封装。它可以帮助开发者有效的隔离 HTML fragment, 并且它可以有自己的样式。通常来说任何在 Shadow DOM 的内容都可以被当作Shadow DOM 的引用都找到。一般常规的 DOM 我们可以通过 document.querySelector('selector') 或者某个元素内部的 element.querySelector('selector') 进行查找。因此我们如何要找到某个 Shadow DOM 内部的一个元素,我们可以通过 shadowRoot.querySelector 来找到。从某种程序上来讲,Shadow DOM 有点类似我们常用的 iframe,它里面内容是独立于当前上下文的,不过我们能够创建 Shadow DOM 我们就能够保持对它的控制。

<div>  
  <div id="example">
    <!-- Pseudo-code used to designate a shadow root -->
    <#shadow-root>
      <style>
      button {
        background: tomato;
        color: white;
      }
      </style>
      <button id="button">This will use the CSS background tomato</button>
    </#shadow-root>
  </div>
  <button id="button">Not tomato</button>
</div>  

上面的代码,我们需要通过声明 <#shadow-root> 来进行标记,标记接下来的内容是 属于 Shadow DOM 里面的,下面代码则展示了我们如何通过 JS 来进行 DOM 操作。

const shadowRoot = document.getElementById('example').attachShadow({ mode: 'open' });  
shadowRoot.innerHTML = `<style>  
button {  
  color: tomato;
}
</style>  
<button id="button">This will use the CSS color tomato <slot></slot></button>`;  

在 Shadow Root 中,我们可以通过使用 <slot></slot> 来对 Document 包含的 内容进行引用。 效果

https://codepen.io/calebdwilliams/pen/rRNJPJ

HTML 模版

HTML 模版,可以帮助我们在常规的文档流创建可复用,并且不需要立即渲染的模版。

<template id="book-template">  
  <li><span class="title"></span> &mdash; <span class="author"></span></li>
</template>

<ul id="books"></ul>  

上面的代码并不会渲染,直到有 Script 开始触发使用它。

const fragment = document.getElementById('book-template');  
const books = [  
  { title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
  { title: 'A Farewell to Arms', author: 'Ernest Hemingway' },
  { title: 'Catch 22', author: 'Joseph Heller' }
];

books.forEach(book => {  
  // 创建模版的实例
  const instance = document.importNode(fragment.content, true);
  // 填充内容
  instance.querySelector('.title').innerHTML = book.title;
  instance.querySelector('.author').innerHTML = book.author;
  // 我们需要把实例添加到 DOM 当中
  document.getElementById('books').appendChild(instance);
});

Template 可以自由定义,你可以在里面包含复杂的 DOM 结构。

演示效果。

小结

随着 Web 发展,前段开发变得越来越复杂,我们越来越需要可复用高独立性的扩展支持,好在 Web Components 发展给大家看到我们在前端高速发展的时候可使用的武器越来越多。随着 ES6/Webpack以及 MVVM 的框架成为主流也验证 Web Components 其设计思想的正确。虽然我们在项目中依旧很少会用到 Web Components 但了解其使用和设计思路还是很有益处的。

扩展阅读

https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements

https://css-tricks.com/an-introduction-to-web-components/

https://developer.mozilla.org/en-US/docs/Web/WebComponents/Usingshadow_DOM

You Can Speak "Hi" to Me in Those Ways