什么是Web Components
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 web 应用中使用它们。 以上是 MDN 中的解释,通俗点讲就是允许开发人员创建可重用的自定义组件,封装后就是一个全新的 HTML 标签,可以像使用 div 标签一样在 HTML 中直接调用。
话不多说,上例子,大家都认识的video标签就是 Web Components 实现的:
从图中可以看到,一个拥有进度条、开始、暂停等丰富功能的 video 标签,原来是一堆基础标签拼出来的。并且可以选中 video 标签,在控制台执行 $0.querySelector('.closed');返回结果是 null, 这就是 shadow DOM 的魅力,天然沙盒。
shadow DOM 又是什么,不要觉得神奇,又是什么新概念,只是web Componnet 的一部分而已。
示例:
<video src="http://vjs.zencdn.net/v/oceans.mp4"></video>为什么我的 video 标签下没有
#shadow-root?打开 Chrome devTool, 控制面板
右上角三个点 - Setting - Preferences - Elements - Show user agent shadow DOM勾选即可,后边自定义标签练习也要用到,建议勾选
Web Components 三大技术
查看代码请点击展开
<card-info></card-info>
<script>
class Info extends HTMLElement {
constructor() {
super();
const template = document.createElement('template');
template.innerHTML = `
<style>
img {
width: 300px;
}
div {
width: 300px;
background-color: #0040ff12;
color: #113b91;
height: fit-content;
background-image: linear-gradient(0deg, #dfd2d2 10%, transparent 0), linear-gradient(90deg, #dfd2d2 10%, transparent 0);
background-size: 10px 10px;
font-weight: bold;
font-size: 20px;
box-shadow: inset 0 0 8px 4px #98a8c9;
padding: 20px 20px 25px;
box-sizing: border-box;
}
</style>
<img src="你家小可爱的照片,如果没有,那你就是小可爱.webp" />
<div>hello Web Componnets</div>
`;
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
}
};
customElements.define('card-info', Info);
</script>
没错,这么几行代码已经涵盖了 Web Componnet 中的三项技术,以下是 MDN 对这三部分内容的介绍🎈
- Custom elements(自定义元素): 一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。
- Shadow DOM(影子 DOM) :一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
- HTML templates(HTML 模板):
<template>和<slot>元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
重点介绍 shaodow DOM
详细文档请移步 MDN,贴一下 MDN 对 shadow DOM 的结构图。
shadow DOM 的特点
- css、js 与外界隔离,互不影响,天然沙盒,在
微前端场景应用
Web Components 的优势
- 不受框架的限制,原生 api 支持
- 对全局污染较小
Web Components 的应用及支持
-
腾讯 Omi 前面拥抱 Web Components ,融合 jsx 造就了一个新的框架
-
Hybrids: 需要注意的是,Hybrids 是用普通函数定义的组件,而非上边我们示例中的 class,好处呢,就是避免了 this 的限制。
-
React 对 Web Components 的支持:zh-hans.reactjs.org/docs/web-co…
React 支持在 Web Components 中使用 React,或者在 React 中使用 Web Components,或者两者共存。
在 React 中使用 Web Componnets
class HelloMessage extends React.Component { render() { return <div>Hello <x-search>{this.props.name}</x-search>!</div>; } }在 Web Componnets 中使用 React
class XSearch extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); const name = this.getAttribute('name'); const url = 'https://www.google.com/search?q=' + encodeURIComponent(name); const root = ReactDOM.createRoot(mountPoint); root.render(<a href={url}>{name}</a>); } } customElements.define('x-search', XSearch); -
Vue 对 Web Components 的支持:
我们认为 Vue 和 Web Components 大体上是互补的技术。Vue 能很好地解析和创建自定义元素。不论是在将自定义元素整合到已有的 Vue 应用中,还是使用 Vue 构建和分发自定义元素,你都能获得很好的支持。
import { defineCustomElement } from 'vue' const MyVueElement = defineCustomElement({ // 在此提供正常的 Vue 组件选项 props: {}, emits: {}, template: `...`, // defineCustomElement 独有特性: CSS 会被注入到隐式根 (shadow root) 中 styles: [`/* inlined css */`] }) // 注册自定义元素 // 注册完成后,此页面上的所有的 `<my-vue-element>` 标签会被更新 customElements.define('my-vue-element', MyVueElement) // 你也可以编程式地实例化这个元素: // (只能在注册后完成此操作) document.body.appendChild( new MyVueElement({ // initial props (optional) }) )
有时间可看看
-
slot 增加 Template 灵活度,用法如下: 可对比 React 的
Render Props, vue 的slot用法
// template 自定义标签名:my-paragraph
<tmeplate>
<p title="我是 template 功能标签">
<slot name="my-text" title="我是外部传入dom, 传什么画什么,与 template 无关">My default text</slot>
</p>
</template>
// my-paragraph 自定义标签消费
<my-paragraph>
<span slot="my-text">Let's have some different text!</span>
</my-paragraph>
-
Custom elements 生命周期 上文中示例只做了最简单的介绍,自定义元素内部是简单的无变化的内容,生命周期可以使其活起来。定义在自定义元素的类定义中的特殊回调函数,影响其行为:
-
connectedCallback: 当自定义元素第一次被连接到文档 DOM 时被调用。 -
disconnectedCallback: 当自定义元素与文档 DOM 断开连接时被调用。 -
adoptedCallback: 当自定义元素被移动到新文档时被调用。 -
attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。