时间:2023-05-29 00:15:02 | 来源:网站运营
时间:2023-05-29 00:15:02 来源:网站运营
Web Componets 实践报告,原生组件开发:<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <hello-custom></hello-custom> <hello-custom></hello-custom> <hello-custom></hello-custom></body><script> class HelloCustom extends HTMLElement { constructor() { super(); let hello = document.createElement('div'); hello.innerHTML = "测试一下自定义元素" this.append(hello) } } window.customElements.define('hello-custom', HelloCustom);</script></html>
this.append
方法把元素加入当前自定义标签。一个自定义标签类就实现了,然后在全局对象customElements
调用define
方法注册我们的组件注意:自定义标签必须是中间有一个连字符,浏览器默认单个单词是原生标签,有连字符的为自定义标签<body> <template id="hello"> <p>测试一下hello</p> <a href="">这里是测试的模板</a> </template></body>
var content = hello.content.cloneNode(true);
。class HelloCustom extends HTMLElement { constructor() { super(); let hello = document.getElementById("hello") var content = hello.content.cloneNode(true); this.append(content) } }
<template id="hello"> <style> p { background-color: blue; color: white; } </style> <p>测试一下hello</p> <a href="">这里是测试的模板</a> </template>
<style> #htllo_test { background-color: red; } </style> <template id="hello"> <style> p { background-color: blue; color: white; } </style> <p id="htllo_test">测试一下hello</p> <a href="">这里是测试的模板</a> </template> ```![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1907d1569174bfa8c68b38b839688d5~tplv-k3u1fbpfcp-watermark.image?) 外部的css样式作用到了组件上面,并且权重更高,把组件内部样式给覆盖了,原本的蓝色背景,变成了红色。用过vue的同学都知道,vue的style标签上面有一个scope属性,可以防止外部样式作用到内部组件上面,在我们的原生组件上面,我们要怎么实现呢,这里就用到了三大api中的最后一个,**Shadow DOM(影子DOM)**### Shadow DOM(影子DOM) 所谓的影子dom,见名知意,就是可以屏蔽外部的影响,很简单吧。我们就不搞那些花里胡哨的说法了,直接开整。 ```js class HelloCustom extends HTMLElement { constructor() { super(); this.shadow = this.attachShadow({mode:'closed'}) // open和closed分别控制是否能被外部js访问 let hello = document.getElementById("hello") var content = hello.content.cloneNode(true); this.shadow.append(content) } } ``` 可以发现,使用非常的简单,只需要加入一条代码 `this.shadow = this.attachShadow({mode:'open'})` 然后在选择添加的时候把我们的内容添加到this.shadow上面就可以了。![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aeb879d690ec49de86e26143b7227a92~tplv-k3u1fbpfcp-watermark.image?) 再次查看效果,可以发现,外部样式已经无法影响到内部,并且,内部的细节以及被隐藏,无法查看内部结构了,这是因为我们在使用shadow dom的时候选择的*mode:closed*,如果选择open,则为可以查看。它的本质是,是否允许外部js直接修改操作组件内部dom。<br> 使用了Shadow DOM之后,可以在template中使用Shadow DOM的专用选择器*host*选择器,它选择的是整个template本身。值得注意的是,它必须显示指定display属性,否则不可见。![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2b9aad0e51d34d7bbbc73338e8d609cd~tplv-k3u1fbpfcp-watermark.image?) 比如鼠标划上自定义元素,左侧无法框选,也无法选中。设置display之后:```html <template id="hello"> <style> :host { display: block; border: 5px solid gray; } p { background-color: blue; color: white; } </style> <p id="htllo_test">测试一下hello</p> <a href="">这里是测试的模板</a> </template>
class HelloCustom extends HTMLElement { // 生命周期 - created constructor() { super(); console.log('created-被执行'); this.shadow = this.attachShadow({ mode: 'closed' }) // open和closed分别控制是否能被外部js访问 let hello = document.getElementById("hello") var content = hello.content.cloneNode(true); this.shadow.append(content) } // 生命周期 - mounted connectedCallback() { console.log('mounted-被执行'); } // 生命周期 - update attributeChangedCallback() { console.log('update-被执行'); } // 生命周期 - destory disconnectedCallback() { console.log('被移出') } }
<template id="hello"> <style> :host { display: block; border: 5px solid gray; } p { background-color: blue; color: white; } </style> <p id="htllo_test"></p> <slot>slot default</slot> <slot name="slot1">slot1</slot> <a href="">这里是测试的模板</a> <slot name="slot2">slot2</slot> </template> <hello-custom title="外部传参测试" id="hello_custom"> <div>我是默认slot</div> <div slot="slot1">name slot1</div> </hello-custom>
<hello-custom title="外部传参测试"></hello-custom>class HelloCustom extends HTMLElement { // 生命周期 - created constructor() { super(); this.shadow = this.attachShadow({ mode: 'closed' }) // open和closed分别控制是否能被外部js访问 let hello = document.getElementById("hello") var content = hello.content.cloneNode(true); content.querySelector("#htllo_test").innerHTML = this.getAttribute("title") this.shadow.append(content) } }
this.getAttribute
就可以获取挂载在外部的参数,然后想怎么操作就怎么操作<hello-custom title="外部传参测试" id="hello_custom"></hello-custom> <button class="test_btn" onclick="test()">测试改变</button>class HelloCustom extends HTMLElement { // 生命周期 - created constructor() { super(); this.shadow = this.attachShadow({ mode: 'closed' }) // open和closed分别控制是否能被外部js访问 let hello = document.getElementById("hello") this.content = hello.content.cloneNode(true); this.shadow.append(this.content) } attributeChangedCallback(name, oldValue, newValue) { this.shadow.querySelector("#htllo_test").innerHTML = newValue console.log("被执行", newValue); } static get observedAttributes() {return ['title', 'l']; } } window.customElements.define('hello-custom', HelloCustom); function test() { let myHello = document.getElementById('hello_custom') myHello.setAttribute("title", "修改后的外部参数测试" + new Date()) // console.log(myHello); }
需要注意的是,如果需要在元素属性变化后,触发 attributeChangedCallback()
回调函数,你必须监听这个属性。这可以通过定义observedAttributes()
get函数来实现,observedAttributes()
函数体内包含一个 return语句,返回一个数组,包含了需要监听的属性名称。static get observedAttributes() {return ['title', 'l']; }
可以看到,已经成功得到回调。function test() { let myHello = document.getElementById('hello_custom') myHello.setAttribute("title", "修改后的外部参数测试" + new Date()) // console.log(myHello); console.log(myHello.shadowRoot); }
this.shoadow
关键词:实践,报告