详解vue3.2新增的defineCustomElement底层原理
目录
- Web Components
- customElements
- 概述
- HTMLTemplateElement 内容模板元素
- 概述
- 常用属性
- ShadowRoot
- 概述
Web Components
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。
相当于是浏览器原生的定义组件的方式,不用通过vue或者react这些框架实现组件的定义
customElements
概述
customElements 是Window对象上的一个只读属性,接口返回一个CustomElementRegistry 对象的引用,可用于注册新的 custom elements,或者获取之前定义过的自定义元素的信息。
HTMLTemplateElement 内容模板元素
概述
HTML内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以(原文为 may be)在运行时使用JavaScript实例化。
将模板视为一个可存储在文档中以便后续使用的内容片段。虽然解析器在加载页面时确实会处理<template>元素的内容,但这样做只是为了确保这些内容有效;但元素内容不会被渲染。
常用属性
content 获取DocumentFragment 元素片段的内容
相当于通过document.createDocumentFragment()创建的元素片段,
<!-- 定义te【文章转自:中东服务器】mplate片段 --> <template id="element-template"> <div>test-template</div> </template> <script> /* 获取template片段 */ const ele = document.getElementById('element-template') ele.content instanceof DocumentFragment //true /* 通过createDocumentFragment创建html片段*/ const div = document.createDocumentFragment('div') div instanceof DocumentFragment //true /* 结论 */ // 定义在html上的template获取它的content相当于和通过createDocumentFragment创建的html片段是一个东西 </script>
ShadowRoot
概述
Shadow DOM API 的 ShadowRoot 接口是一个 DOM 子树的根节点, 它与文档的主 DOM 树分开渲染。
你可以通过使用一个元素的 Element.shadowRoot 属性来检索它的参考,假设它是由 Element.attachShadow() 创建的并使 mode 设置为 open.
通过 Element.attachShadow()挂载影子DOM
完整的演示代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <test-shadow-root></test-shadow-root> <template id="temEle"> <style> .main{ color: #f00; } </style> <div class="main"> 我是template片段 <!-- 使用插槽 --> <slot name="header"></slot> </div> </template> <test-template-ele> <!-- 定义插槽 --> <style> .slot{ color: rgb(87, 28, 223); } </style> <div class="slot" slot="header">我是slot</div> </test-template-ele> <!-- 生命周期测试 --> <div id="moveDiv"> <button id="add">添加</button> <button id="update">更新</button> <button id="move">移动</button> <button id="remove">删除</button> </div> <!-- 通过is挂载 --> <div is="test-is-com"> <div>AAA</div> </div> <script> /* 自定义web-components */ customElements.define('test-shadow-root', class extends HTMLElement { /* 当test-shadow-root组件被挂载到DOM上时,执行构造函数 */ constructor() { super() const shadowRoot = this.attachShadow({mode: 'open'}) //给指定的元素挂载影子DOM // 当执行 this.attachShadow()方法时,shadowRoot被挂载构造函数中,可以通过this访问 // mode open shadow root元素可以从js外部访问根节点 // mode closed 拒绝从js外部访问关闭的shadow root节点 // console.log('执行', this) const div = document.createElement('div') div.textContent = '我是div的内容' // shadowRoot.appendChild() // console.log('this', this.shadowRoot) shadowRoot.appendChild(div) // this.shadowRoot === shadowRoot true } }) /* 通过template自定义HTMLTemplateElement */ customElements.define('test-template-ele', class extends HTMLElement { constructor() { super() const temEle = document.querySelector('#temEle') const templateContent = temEle.content //获取html片段 // console.log('AA', templateContent instanceof DocumentFragment) //true // templateContent // 创建影子DOM,用于挂载template的片段 const shadowRoot = this.attachShadow({mode: 'open'}) // console.log('shadowRoot', shadowRoot) shadowRoot.appendChild(templateContent) } }) /* 通过js创建web-组件,测试生命周期函数 */ class LifeCycle extends HTMLElement { static get observedAttributes() { //必须添加组件上的属性,才能触发attributeChangedCallback return ['c', 'l']; } constructor() { super() const shadowRoot = this.attachShadow({mode: 'open'}) const div = `<div> <heaher>我的头</header> <div>内容</div> <footer>尾部</footer> </div>` shadowRoot.innerHTML = div } connectedCallback() { //添加时,执行 console.log('添加') } disconnectedCallback() {//删除时,执行 console.log('disconnectedCallback') } adoptedCallback() { console.log('adoptedCallback') } attributeChangedCallback() { //属性被改变时 console.log('attributeChangedCallback') } } customElements.define('test-life-cycle', LifeCycle) const add = document.querySelector('#add') const update = document.querySelector('#update') const move = document.querySelector('#move') const remove = document.querySelector('#remove') const moveDiv = document.querySelector('#moveDiv') let testLifeDom = null function random(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } add.addEventListener('click', () => { testLifeDom = document.createElement('test-life-cycle') //创建上面定义的自定义组件 // console.log('testLifeDom', testLifeDom) document.body.appendChild(testLifeDom); testLifeDom.setAttribute('l', '100'); testLifeDom.setAttribute('c', 'red'); console.log('add', testLifeDom) }) update.addEventListener('click', () => { const div = '<div>更新后</div>' // console.log('update', testLifeDom.shadowRoot.innerHTML) testLifeDom.shadowRoot.innerHTML = div testLifeDom.setAttribute('l', random(50, 200)); testLifeDom.setAttribute('c', `rgb(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)})`); }) move.addEventListener('click', () => { console.log('moveDiv', moveDiv) moveDiv.appendChild(testLifeDom) }) remove.addEventListener('click', () => { console.log('remove') document.body.removeChild(testLifeDom); }) /* 通过is挂载组件 */ customElements.define('test-is-com', class extends HTMLDivElement { constructor() { super() console.log('挂载', this.innerHTML) // 通过挂载,this,就是当前被挂载的元素实例,通过这种方式,可以实现一些操作 } }, {extends: 'div'}) </script> </body> </html>
到此这篇关于详解vue3.2新增的defineCustomElement底层原理的文章就介绍到这了,更多相关vue3.2 defineCustomElement内容请搜索hwidc以前的文章或继续浏览下面的相关文章希望大家以后多多支持hwidc!
【文章出处:美国多ip服务器 请说明出处】