组件是前端的发展方向,现在流行的 React 和 Vue 都是组件框架。如今 Web Components 被越来越多的浏览器所支持,Web Components 或许是未来的方向。
Web Components 的组成主要是由这三种组成,它们可以封装自定义功能的元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
- Custom elements(自定义元素):允许自定义一个标签,以及一些操作,然后可以像普通标签一样使用它
- Shadow DOM(影子DOM):可以对脚本和样式进行隔离,不用担心外部对其由影响
- HTML templates(HTML模板):<template> 和 <slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
自定义元素
CustomElementRegistry 接口的实例用来注册一个自定义元素,window.customElements 获取去到 CustomElementRegistry 实例。customElements.define() 方法用来注册一个 custom element,该方法接受以下参数:
- 表示所创建的元素名称的符合 DOMString 标准的字符串。注意,custom element 的名称不能是单个单词,且其中必须要有短横线。
- 用于定义元素行为的 类 。
- 可选参数,一个包含 extends 属性的配置对象,是可选参数。它指定了所创建的元素继承自哪个内置元素,可以继承任何内置元素。
像这样定义一个自定义元素<user-p>,并且继承元素<p>
customElements.define( |
自定义元素的使用也分两种情况
一种是如果元素不继承其他内建 HTML 元素,只继承 HTMLElement,可以直接像普通标签一样使用
<user-p></user-p> |
如果是继承了其他元素,比如像上面那个例子 HTMLParagraphElement
<p is='user-p'></p> |
生命周期回调函数
- connectedCallback:首次被插入文档DOM时,被调用。
- disconnectedCallback:从文档DOM中删除时,被调用。
- adoptedCallback:被移动到新的文档时,被调用。
- attributeChangedCallback:增加、删除、修改自身属性时,被调用。
如果需要在元素属性变化后,触发 attributeChangedCallback()回调函数,你必须监听这个属性。这可以通过定义 observedAttributes() get函数来实现,observedAttributes()函数体内包含一个 return 语句,返回一个数组,包含了需要监听的属性名称:
static get observedAttributes() {return ['name', 'style']; } |
Shadow DOM
Shadow DOM 可以将一个隐藏的、独立的 DOM 附加到一个元素上,可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。
- Shadow host:一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上。
- Shadow tree:Shadow DOM 内部的 DOM 树。
- Shadow boundary:Shadow DOM 结束的地方,也是常规 DOM 开始的地方。
- Shadow root: Shadow tree 的根节点。
像<video>就是用 Shadow DOM 封装的
自定义Shadow DOM
可以使用 Element.attachShadow() 方法来将一个 shadow root 附加到任何一个元素上,方法接受一个参数
attachShadow 参数 |
简单例子
<style> |
效果如下,可以看到外部样式是不会影响里面元素的,但是如果是样式是继承祖先元素的是会穿透进去的
这三个都是用来选定 宿主元素 的
- :host 当前 ShadowDOM 宿主元素
- :host() 在宿主元素上查找,比如上面的 :host(#demo) 就是当宿主元素 id=’demo’ 时候生效
- :host-context() 在当前 ShadowDOM 宿主元素的祖先节点中查找,比如 :host-context(.test) 可以一直往宿主元素祖先上找,符合就生效
HTML模板
template 主要作用就是避免重复去创建那些标签结构。比如当一个组件被重复使用时候,如果不用模板的话,会一遍又一遍的去创建组件类的标签结构,使用 template 这样会避免这样重复的创建标签结构。
template 不会再 DOM 上显示,举例:
<template id="my-template"> |
使用 js 去获取它
let template = document.getElementById('my-template'); |
组合使用
<my-div image='/images/logo/admin_template.png'> |