customElements.define
在MDN官方文档中,如果你想要使用自定义标签,可以使用customElement类中define方法(IE7以下浏览器不支持),
使用:customElements.define(‘myselfTagName’, myselfClass, extendsObj);
参数:
myselfTagName: 自定义标签名
myselfClass: 自定义标签的类对象,(主要功能在这里实现,一般在自定义标签绑定变量、事件、指令或者是渲染条件)
extendsObj: 内置并继承的元素(包裹着自定义标签的对象,一般不使用,毕竟谁会闲的无聊把基本标签封装成自定义标签然后填充一堆属性,语义化也说不通啊)
attachShadow
官方文档对于shadow DOM解释很模糊,简单的说就是DOM的’一体双魂’,拥有同样的函数和方法,但是Shadow DOM比被附加DOM更多的功能,前者具有独自的作用域,并且与外界DOM分隔。(这个作用就是shadow DOM的核心功能,它可以使你编写的DOM与css与其他区域互不影响,相当于vue中css样式<style scoped> </style>的作用);
shadow DOM弥补了customElements缺少隔离作用域(DOM和css作用域)的缺陷。
shadom DOM Root的创建方法: this.attachShadow({mode: ‘open’});
this: shadom DOM对象
mode: 开启js调用shadow DOM
代码示范
coding.... 莫道征途路漫漫
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Pop-up info box — web components</title>
</head>
<body>
<h1>Pop-up info widget - web components</h1>
<form>
<div>
<label for="cvc">Enter your CVC <popup-info img="img/alt.png" data-text="Your card validation code (CVC) is an extra security feature — it is the last 3 or 4 numbers on the back of your card."></label>
<input type="text" id="cvc">
</div>
</form>
</body>
<script>
/**
*
* @description:将shadow root附加到customelement上,
然后通过一系列DOM操作创建custom element的内部阴影DOM结构,
再将其附加到 shadow root上,最后再将一些CSS附加到
shadow root的style节点上。
*/
class PopUpInfo extends HTMLElement {
constructor() {
// 必须使用super初始化customElements类的构造器
super();
// 创建shadom Dom Root,该Root 挂载在自定义DOM上,该DOM Root节点是一个真实节点。
const shadow = this.attachShadow({mode: 'open'});
// Create spans
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
let icon = document.createElement('span'),
info = document.createElement('span'),
text = this.getAttribute('data-text');
icon.setAttribute('class', 'icon');
icon.setAttribute('tabindex', 0);
info.textContent = text;
info.setAttribute('class', 'info');
let imgUrl = this.hasAttribute('img') ? this.getAttribute('img'): 'img/default.png',
img = document.createElement('img');
img.src = imgUrl;
icon.appendChild(img);
// 优化样式
const style = document.createElement('style');
console.log(style.isConnected);
style.textContent = `
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
opacity: 0;
transition: 0.6s all;
position: absolute;
bottom: 20px;
left: 10px;
z-index: 3;
}
img {
width: 1.2rem;
}
.icon:hover + .info, .icon:focus + .info {
opacity: 1;
}
`;
// 插入shadow dom Root
shadow.appendChild(style);
console.log(style.isConnected);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
// 自定义标签
customElements.define('popup-info', PopUpInfo);
</script>
</html>
思考
自定义标签的使用减少了我们频繁编写一堆冗余、深层嵌套的代码,提高了速率。然而,如果我们看页面源码会发现customElements.define不会消除自定义标签,自定义标签如果绑定了大量的数据、事件、敏感信息,页面上又完全显示出来,这就增加前端页面的不安全性。如何保证开发者即使用自定义标签又不会编译自定义标签从而导致DOM的过度挂载和数据的泄漏(不建议remove自定义标签,频繁操作DOM太消耗内存了),值得思考…