Web Components —— Web 组件

简介: Web Components —— Web 组件

image.png


前言

在重学 JavaScript 过程中,了解到了 Web 组件,而其中的一些知识点总感觉和 vuejs 中的某些概念很相似,比如 Web 组件中涉及的内容:

  • HTML 模板,即 template 标签
  • 自定义元素
  • 影子 DOM 和 slot 标签
  • 影子 DOM 实现样式隔离

那么下面就一起看看 Web 组件的这些内容和 vue 中的某些概念相似在哪吧!

image.png

Web Components

Web 组件到底是什么?

Web 组件其实就是一套用于增强 DOM 行为的工具,其内容包括 影子 DOM自定义元素HTML 模板 等.

目前 Web Components 没有得到广泛应用,主要是因为存在以下问题:

  • 没有统一的 "Web Components" 规范
  • Web 组件存在向后不兼容的版本问题
  • 浏览器实现极其不一致

由于存在这些问题,因此使用 Web 组件通常需要引入一个 Web 组件库,用于模拟浏览器中缺失的 Web 组件. 比如 PolymerLitElement,新项目更推荐使用 LitElement.

image.png

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>
复制代码

image.png

在浏览器中通过开发者工具检查网页内容时,可以看到 <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 class="green">Make me green!</p>
  </template>
  <script>
    let divRoot = document.querySelector("#root");
    let tpl = document.querySelector("#tpl").content;
    setTimeout(() => {
      divRoot.appendChild(tpl);
    }, 3000);
  </script>
</body>
复制代码

template 模板脚本

如果在 template 标签中存在对应的 js 脚本,那么脚本执行可以推迟到将 DocumentFragment 的内容实际添加到 DOM 树,即 延迟执行 js 脚本.

直接看下面的例子:

<body>
    <div id="foo"></div>
    <template id="bar">
     <script>
         console.log('Template script executed');
     </script>
    </template>
    <script>
    const fooElement = document.querySelector('#foo');
    const barTemplate = document.querySelector('#bar');
    const barFragment = barTemplate.content;
    console.log('About to add template');// 1. About to add template
    fooElement.appendChild(barFragment);//2. Template script executed
    console.log('Added template');// 3. Added template
    </script>
</body>
复制代码

影子 DOM —— shadow DOM

首先来看下面的问题,然后思考一下:

如何给 HTML 中众多相似的结构去渲染不同的样式呢?通常情况下,为了给每个子树应用唯一的样式,又不使用 style 属性,就需要给每个子树添加一个唯一的类名,然后通过相应的选择符为它们添加样式。

存在的问题:

  • 必须通过 唯一样式选择器 决定渲染对应的样式渲染
  • 样式全部作用于顶级 DOM 树中,即使当前展示的内容需要使用很少的样式
  • 没有真正实现 CSS 样式的隔离,很容易因为书写问题导致 样式冲突

理想情况下,应该能够把 CSS 限制在使用它们的 DOM 上。

影子 DOM 是什么?

通过影子 DOM 就可以将一个 完整的 DOM 树 作为节点添加到 父 DOM 树

即可以实现 DOM 封装,意味着 CSS 样式和 CSS 选择符可以限制在影子 DOM 子树中,而不是作用于整个顶级 DOM 树。

创建影子 DOM

影子 DOM 是通过 attachShadow() 方法创建并添加给有效 HTML 元素的:

  • 影子宿主(shadow host),即容纳影子 DOM 的元素
  • 影子根(shadow root),即影子 DOM 的根节点
  • attachShadow() 方法需要一个 shadowRootInit 对象,即这个对象必须包含一个 mode 属性,值为 "open" 或 "closed"
  • mode 属性值为 "open" 的影子 DOM 的引用可通过 shadowRoot 属性在 HTML 元素上获得,属性值 "closed" 影子 DOM 的引用则无法获取
document.body.innerHTML = `
    <div id="foo"></div>
    <div id="bar"></div>
`;
const foo = document.querySelector('#foo');
const bar = document.querySelector('#bar');
// 创建不同 dom 元素的影子节点,一个 dom 节点只能有一个 影子 DOM
const openShadowDOM = foo.attachShadow({ mode: 'open' });
const closedShadowDOM = bar.attachShadow({ mode: 'closed' });
// 直接访问影子根节点
console.log(openShadowDOM); // #shadow-root (open)
console.log(closedShadowDOM); // #shadow-root (closed)
// 为影子 DOM 添加内容和样式,这里的样式是完全隔离的,并不会发生样式冲突
openShadowDOM.innerHTML = `
 <p>this is red</p>
 <style>
  p{
    background: red;
  }
 </style>
`
closedShadowDOM.innerHTML = `
 <p>this is blue</p>
 <style>
  p{
    background: blue;
  }
 </style>
`
// 通过影子宿主访问影子根节点 
console.log(foo.shadowRoot); // #shadow-root (open)
console.log(bar.shadowRoot); // null
复制代码

image.png

合成与影子 DOM 槽位 slot

影子 DOM 是为自定义 Web 组件设计的,为此需要支持嵌套 DOM 片段,也就是说位于 影子宿主 中的 HTML 需要一种机制以渲染到影子 DOM中去,但这些 HTML 又不需要存在于影子 DOM 树中.

[ 影子 DOM 具有最高优先级 ]

正常情况下,影子 DOM 一添加到元素中,浏览器就会赋予它 最高优先级,优先渲染它的内容而不是原来的 dom 内容,比如下面的例子:

document.body.innerHTML = `
    <div id="foo">
      <h1>I'm foo's child</h1>
    </div>
`;
const foo = document.querySelector('#foo');
const openShadowDOM = foo.attachShadow({
  mode: 'open'
});
// 为影子 DOM 添加内容
openShadowDOM.innerHTML = `
  <p>this is openShadowDOM content</p>
`
复制代码

image.png

[ <slot> 标签 ]

为了显示影子宿主中原本存在的 HTML 内容,我们需要使用 <slot> 标签指示浏览器在哪里放置原来的 HTML 内容,将上面的例子修改成如下形式:

document.body.innerHTML = `
    <div id="foo">
      <h1>I'm foo's child</h1>
    </div>
`;
const foo = document.querySelector('#foo');
const openShadowDOM = foo.attachShadow({
  mode: 'open'
});
// 为影子 DOM 添加内容
openShadowDOM.innerHTML = `
  <p>this is openShadowDOM content</p>
   <slot></slot>
`
复制代码

image.png


目录
相关文章
|
4月前
|
JavaScript 前端开发 开发者
哇塞!Vue.js 与 Web Components 携手,掀起前端组件复用风暴,震撼你的开发世界!
【8月更文挑战第30天】这段内容介绍了Vue.js和Web Components在前端开发中的优势及二者结合的可能性。Vue.js提供高效简洁的组件化开发,单个组件包含模板、脚本和样式,方便构建复杂用户界面。Web Components作为新兴技术标准,利用自定义元素、Shadow DOM等技术创建封装性强的自定义HTML元素,实现跨框架复用。结合二者,不仅增强了Web Components的逻辑和交互功能,还实现了Vue.js组件在不同框架中的复用,提高了开发效率和可维护性。未来前端开发中,这种结合将大有可为。
167 0
|
4月前
|
Web App开发 JavaScript 前端开发
[译] 用 Web Worker 改善 Vue 组件性能
[译] 用 Web Worker 改善 Vue 组件性能
|
2月前
|
前端开发 JavaScript 开发者
Web组件:一种新的前端开发范式
【10月更文挑战第9天】Web组件:一种新的前端开发范式
64 2
|
2月前
|
前端开发 JavaScript Go
前端开发趋势:从响应式设计到Web组件的探索
【10月更文挑战第1天】前端开发趋势:从响应式设计到Web组件的探索
42 3
|
1月前
|
消息中间件 监控 Kafka
Apache Kafka 成为处理实时数据流的关键组件。Kafka Manager 提供了一个简洁的 Web 界面
随着大数据技术的发展,Apache Kafka 成为处理实时数据流的关键组件。Kafka Manager 提供了一个简洁的 Web 界面,方便管理和监控 Kafka 集群。本文详细介绍了 Kafka Manager 的部署步骤和基本使用方法,包括配置文件的修改、启动命令、API 示例代码等,帮助你快速上手并有效管理 Kafka 集群。
47 0
|
5月前
|
Web App开发 前端开发 安全
2024年新一代WebOffice内嵌网页组件,Web网页在线编辑Word/Excel/PPT
WebOffice控件面临兼容性、用户体验和维护难题。随着浏览器更新,依赖插件的技术不再适用,如Chrome不再支持NPAPI和PPAPI。产品普遍不支持多版本Office并存,定制能力弱,升级复杂。猿大师办公助手提供了解决方案,它兼容多种浏览器,包括最新版和国产浏览器,不依赖插件,支持文档对比,具有丰富的功能和接口,兼容多种Office版本,允许源码级定制,提供终身技术支持,并实现静默在线升级。适用于多种行业和操作系统。
324 11
|
4月前
|
数据可视化 数据挖掘 持续交付
Axure Web端元件库:从Quick UI到500+组件的飞跃
在快速变化的数字世界中,产品设计不仅仅是功能的堆砌,更是用户体验的精心雕琢。原型设计作为产品开发过程中的关键环节,其重要性不言而喻。Axure,作为业界领先的原型设计工具,凭借其强大的交互设计和丰富的功能,赢得了全球设计师和开发者的信赖。而Axure Web端元件库,则是这一平台上的一颗璀璨明珠,它以超过500个精心设计的组件为基础,为设计师们打开了一扇通往高效、高质量原型设计的大门。
191 0
|
5月前
|
JavaScript 前端开发 API
Web Components详解-HTML Templates
Web Components详解-HTML Templates
90 6
|
5月前
|
设计模式 JavaScript 前端开发
Web Components详解-组件通信
Web Components详解-组件通信
104 6
|
5月前
|
JavaScript 前端开发
Web Components详解-Shadow DOM样式控制
Web Components详解-Shadow DOM样式控制
145 3