注: 本系列主要是探讨web components的概念和使用痛点, 旨在让读者更加了解web components的优势和痛点, 系列参考:
- 你不知道的web component系列——改造Vite模版实现一个自定义元素
- 你不知道的web component系列——改造Vite模版了解shadowDom和插槽-CSDN博客
前言
SSR(server side rendering)对于我们前端开发是非常常见的,它的出现主要是因为我们有着下面的需求:
- SEO优化, 我们希望爬虫在抓取页面的时候也可以获取到我们完整的网页信息,如果在用户禁用js的情况下, 我们的网页应该也可以正常运行
- 网页页面性能LCP等核心网页指标优化
而我们前面几节实现的web component都是命令式的编程方式, 比如:
const goalEl = document.getElementById('goal')
const shadowRoot = goalEl.attachShadow({mode: 'open'})
shadowRoot.innerHTML = '<h1>Hello World!</h1>';
这样的操作只能在CSR(client side rendering)中使用, 这样会导致我们的页面会有一定时间的白屏以及可能的抖动,这些web components存在的痛点都是我们要引入新的声明式命令的原因——declarative-shadow-dom
声明式shadow-dom
我们在前面章节有介绍到<template></template>这个元素, 当浏览器解析到它时就会默认忽略, 而我们的声明式shadow-dom就是一个有着shadowrootmode属性的template元素,实现如下:
<host-element>
<template shadowrootmode="open">
<slot></slot>
</template>
<h2>Light content</h2>
</host-element>
因为vite本身会在本地跑起一个服务器, 因此我们只需要打开浏览器查看网络状态栏(为了更好的对比差异, 我们打开3g的过滤选项):
显然这和我们实际想要呈现给用户的页面差异很大,并且在LCP和SEO搜索上显然是落后的,这也是我们为什么要使用declarative-shadow-dom的原因!
兼容declarative shadow dom
当我们在某些浏览器中可能不兼容declarative shadow dom, 兼容的方式就是我们自己写一个polyfill,大致思路是把每一个具有template shadow root mode属性的子元素通过appendChild的方式挂载到我们对应的父元素身上:
(function attachShadowRoots(root) {
root.querySelectorAll("template[shadowrootmode]").forEach(template => {
const mode = template.getAttribute("shadowrootmode");
const shadowRoot = template.parentNode.attachShadow({ mode });
shadowRoot.appendChild(template.content);
template.remove();
attachShadowRoots(shadowRoot);
});
})(document);
水合(Hydration)
前面我们只是挂载了相关的静态元素到页面上, 如果我们希望这个组件是一个交互式的, 用户的操作可以改变对应的状态, 该如何实现web components的hydrate尼?
<menu-toggle>
<template shadowrootmode="open">
<button>
<slot></slot>
</button>
</template>
Open Menu
</menu-toggle>
<script>
class MenuToggle extends HTMLElement {
constructor() {
super();
const internals = this.attachInternals();
// 用于判断是否使用了declarative shadow dom
let shadow = internals.shadowRoot;
if (!shadow) {
shadow = this.attachShadow({
mode: 'open'
});
shadow.innerHTML = `<button><slot></slot></button>`;
}
shadow.firstChild.addEventListener('click', toggle);
}
}
customElements.define('menu-toggle', MenuToggle);
</script>
总结
web components技术现在还是处于发展中, 很多的功能一旦我们的项目需求发生改变, 可能很难向Vue,React那样快速的找到对应的解决方案并达到我们的生产需求, web components所带来的天然性隔离其实在各大主流的框架中也都有实现并且效果不错, 也许我们根本用不到web components?
但是,考虑到下面的场景, 笔者认为 web components还是很值得去考虑的:
- 跨页面的公用组件, 比如一些导航工具, 弹窗等等
- 跨团队,不同的团队使用的不同框架时就可以使用web components来适用.
- 跨项目, 很多时候我们都面临着对老旧项目的维护和更新, web components来嵌入就是一个不错的选择.
参考
GitHub - mfreed7/declarative-shadow-dom: Declarative Shadow DOM feature development
HTML Standard
版权归原作者 ghtty2 所有, 如有侵权,请联系我们删除。