前言
在重学 JavaScript 过程中,了解到了 Web 组件,而其中的一些知识点总感觉和 vuejs 中的某些概念很相似,比如 Web 组件中涉及的内容:
- HTML 模板,即 template 标签
- 自定义元素
- 影子 DOM 和 slot 标签
- 影子 DOM 实现样式隔离
那么下面就一起看看 Web 组件的这些内容和 vue 中的某些概念相似在哪吧!
Web Components
Web 组件到底是什么?
Web 组件其实就是一套用于增强 DOM 行为的工具,其内容包括 影子 DOM、自定义元素 和 HTML 模板 等.
目前 Web Components 没有得到广泛应用,主要是因为存在以下问题:
- 没有统一的 “Web Components” 规范
- Web 组件存在向后不兼容的版本问题
- 浏览器实现极其不一致
由于存在这些问题,因此使用 Web 组件通常需要引入一个 Web 组件库,用于模拟浏览器中缺失的 Web 组件. 比如 Polymer、LitElement,新项目更推荐使用 LitElement.
HTML 模板 —— template 标签
我们可以先思考下面的问题,并尝试给出一些解决方法。
问题:如何把对应的三个背景颜色分别为红绿蓝的
p
标签,3s 后动态渲染在指定的位置中,如<div id="root"></div>
?
方案一: 使用 innerHtml
let divRoot = document.querySelector("#root");
setTimeout(()=>{
divRoot.innerHTML = `
<p class="red">Make me red!</p>
<p class="blue">Make me blue!</p>
<p class="green">Make me green!</p>
`
},3000);
方案二: 使用 createElement + createDocumentFragment + appendChild
let divRoot = document.querySelector("#root");
let colors = ['red','blue','green'];
let fragment = document.createDocumentFragment();
for (const color of colors) {
const p = document.createElement('p');
p.className = color;
p.innerText = `Make me ${
color}!`
fragment.appendChild(p);
}
setTimeout(()=>{
divRoot.appendChild(fragment);
},3000);
通过 方案一 和 方案二 都能实现对应的效果,但是对于书写 HTML 结构来讲都是不友好的,首先就是它们都无法做到像直接书写 HTML 时的友好提示,其次就是它们都只适用结构非常简单的内容,一旦结构内容有多层嵌套时,单纯设计 html 结构就变得很复杂。
使用 <template>
标签
PS:
<template>
标签是 HTML 中存在的,并不是 vue 中特有的,不要混淆.
在有 Web 组件之前,一直缺少基于 HTML 解析构建 DOM 子树,然后在需要时再把这个子树渲染出来的机制.
在 Web 组件中,可以通过使用 <template>
标签提前在页面中写出特殊标记,让浏览器自动将其解析为 DOM 子树,但跳过渲染. 如下:
<body>
<template id="tpl">
<p>I'm inside a custom element template!</p>
</template>
</body>
在浏览器中通过开发者工具检查网页内容时,可以看到 <template>
标签中渲染的节点内容 是基于 DocumentFragment,而 DocumentFragment 也是批量向 HTML 中添加元素的高效工具,此时的 DocumentFragment 就像一个对应子树的最小化 document 对象,也就是说,如果需要操作 <template>
标签中节点,必须要先获取对应 DocumentFragment 的引用,即 document.querySelector('#tpl').content
.
下面是通过 <template>
标签实现上面问题的解决方案:
<body>
<div id="root"></div>
<template id="tpl">
<p class="red">Make me red!</p>
<p class="blue">Make me blue!</p>
<p