详解vue3.2新增的defineCustomElement底层原理
Web Components
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们。
相当于是浏览器原生的定义组件的方式,不用通过vue或者react这些框架实现组件的定义
customElements
概述
customElements 是Window对象上的一个只读属性,接口返回一个CustomElementRegistry 对象的引用,可用于注册新的 custom elements,或者获取之前定义过的自定义元素的信息。
HTMLTemplateElement 内容模板元素
概述
HTML内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以(原文为 may be)在运行时使用JavaScript实例化。
将模板视为一个可存储在文档中以便后续使用的内容片段。虽然解析器在加载页面时确实会处理<template>元素的内容,但这样做只是为了确保这些内容有效;但元素内容不会被渲染。
常用属性
content 获取DocumentFragment 元素片段的内容
相当于通过document.createDocumentFragment()创建的元素片段,
<!-- 定义template片段 -->
<template id="element-template">
<div>test-template</div>
</template>
<script>
const ele = document.getElementById('element-template')
ele.content instanceof DocumentFragment //true
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>
customElements.define('test-shadow-root', class extends HTMLElement {
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
}
})
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)
}
})
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);
})
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内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341