首页>>前端>>Vue->深度解析vue3.2中defineCustomElement底层原理

深度解析vue3.2中defineCustomElement底层原理

时间:2023-11-29 本站 点击:1

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片段--><templateid="element-template"><div>test-template</div></template><script>/*获取template片段*/constele=document.getElementById('element-template')ele.contentinstanceofDocumentFragment//true/*通过createDocumentFragment创建html片段*/constdiv=document.createDocumentFragment('div')divinstanceofDocumentFragment//true/*结论*///定义在html上的template获取它的content相当于和通过createDocumentFragment创建的html片段是一个东西</script>

ShadowRoot

概述

Shadow DOM API 的 ShadowRoot 接口是一个 DOM 子树的根节点, 它与文档的主 DOM 树分开渲染。

你可以通过使用一个元素的 Element.shadowRoot 属性来检索它的参考,假设它是由 Element.attachShadow() 创建的并使 mode 设置为 open.

通过 Element.attachShadow()挂载影子DOM

完整的演示代码

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title></head><body><test-shadow-root></test-shadow-root><templateid="temEle"><style>.main{color:#f00;}</style><div>我是template片段<!--使用插槽--><slotname="header"></slot></div></template><test-template-ele><!--定义插槽--><style>.slot{color:rgb(87,28,223);}</style><divslot="header">我是slot</div></test-template-ele><!--生命周期测试--><divid="moveDiv"><buttonid="add">添加</button><buttonid="update">更新</button><buttonid="move">移动</button><buttonid="remove">删除</button></div><!--通过is挂载--><divis="test-is-com"><div>AAA</div></div><script>/*自定义web-components*/customElements.define('test-shadow-root',classextendsHTMLElement{/*当test-shadow-root组件被挂载到DOM上时,执行构造函数*/constructor(){super()constshadowRoot=this.attachShadow({mode:'open'})//给指定的元素挂载影子DOM//当执行this.attachShadow()方法时,shadowRoot被挂载构造函数中,可以通过this访问//modeopenshadowroot元素可以从js外部访问根节点//modeclosed拒绝从js外部访问关闭的shadowroot节点//console.log('执行',this)constdiv=document.createElement('div')div.textContent='我是div的内容'//shadowRoot.appendChild()//console.log('this',this.shadowRoot)shadowRoot.appendChild(div)//this.shadowRoot===shadowRoottrue}})/*通过template自定义HTMLTemplateElement*/customElements.define('test-template-ele',classextendsHTMLElement{constructor(){super()consttemEle=document.querySelector('#temEle')consttemplateContent=temEle.content//获取html片段//console.log('AA',templateContentinstanceofDocumentFragment)//true//templateContent//创建影子DOM,用于挂载template的片段constshadowRoot=this.attachShadow({mode:'open'})//console.log('shadowRoot',shadowRoot)shadowRoot.appendChild(templateContent)}})/*通过js创建web-组件,测试生命周期函数*/classLifeCycleextendsHTMLElement{staticgetobservedAttributes(){//必须添加组件上的属性,才能触发attributeChangedCallbackreturn['c','l'];}constructor(){super()constshadowRoot=this.attachShadow({mode:'open'})constdiv=`<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)constadd=document.querySelector('#add')constupdate=document.querySelector('#update')constmove=document.querySelector('#move')constremove=document.querySelector('#remove')constmoveDiv=document.querySelector('#moveDiv')lettestLifeDom=nullfunctionrandom(min,max){returnMath.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',()=>{constdiv='<div>更新后</div>'//console.log('update',testLifeDom.shadowRoot.innerHTML)testLifeDom.shadowRoot.innerHTML=divtestLifeDom.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',classextendsHTMLDivElement{constructor(){super()console.log('挂载',this.innerHTML)//通过挂载,this,就是当前被挂载的元素实例,通过这种方式,可以实现一些操作}},{extends:'div'})</script></body></html>

作者:artist


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Vue/807.html