谈谈WebComponents | 前端开发

news2024/11/26 9:28:48

eeaa637bb0b3ae55dbd787ebd793ccdc.png

一、 源起

让我们以一个例子开始。

假设我们要做一个环形进度条,它可以:

1、根据进度数值的不同,计算出百分比,以渲染对应的角度值。

2、根据设置的进度不同,我们用不同的颜色加以区分。

3、在环的中间我们以动画递增的方式显示进度。

最终的效果,大致如下图:

c54e9bc45ef1e17812de3890a4cb4860.gif

除了直接用组件库,聪明的你肯定已经想到了多种解决办法。如使用现代前端框架React/Vue/Angular/SvelteJS/SolidJS等等,你可能会找到或编写对应的组件,通过相应数据状态的变更,完成相对复杂的交互;又如在小快灵的项目下,用jQuery的Widget开发也是一个不错的选择;再或者,你可以点开你的HTML+JavaScript+CSS技能树,纯手工打造一个。这都是可以完成的任务。

这里[1]就是一个针对这个需求的实现。

当然,在完成之后,你可能会考虑对组件做一些提炼,下次再遇到同样的需求,你就可以气定神闲地“开箱即用”。通常,我们希望撰写的代码能够实现在UI以及行为层面的复用。所以,以组件为单位进行代码复用的需求也就呼之欲出。

实际上,除了Web前端外,各种相关的界面技术,比如安卓和苹果App、Windows软件、Qt以及Flutter等等,都发展出了类似的组件化技术。可以说,组件化是界面技术发展到一定复杂程度的必然产物。

为了放心地复用组件,除了代码层面的复用方案,也要包含一定的隔离特性:我们希望元素的样式、行为能够不被其他的代码干扰,也不会干扰到页面其他的元素,即存在一定的隔离性。考虑下面的代码:

5843f8983036b784ded9166b827430aa.png

考虑上述第10行到20行,以及21行到29行分别来自不同的组件。这里第二个组件的加入就会影响第一个组件的行为。第一个组件也在完全不知情的情况下被莫名其妙地变更了行为、样式。

当然,这样的代码是精心简化过的,实际上的工程代码不会这样撰写。但复杂的代码会造成问题被隐藏的更深,更加难以发现。我们当然可以直接诘问开发者的虑事不周,不过更理智的做法是提炼一些工程化的方法来避免这种问题的发生。比如Vue框架中的scoped样式。归根到底的问题在于,早期的HTML、CSS缺乏封装所必须的特性。

为了弥补这一缺陷,技术人员做了各种探索。

“上古时期”,微软在IE系列曾实现过一种名曰“HTC”的技术,我们甚至还能从互联网上找到这个技术的蛛丝马迹[2]。它实现了组件模版、样式、行为的复用和隔离方案。然而这项技术是IE Only的技术,后面随着大厂博弈以及各种标准化方案的诞生,这个方案在IE10以后便逐渐退出历史舞台。

Firefox在2007年左右也曾经支持过一个封装方案,叫XML Binding Language[3]。不过这项技术也由于主要在Firefox支持,也已经逐步淡出。

前端的框架如Angular、React、Vue等等,都提供了组件的复用和行为隔离的方案。不过由于浏览器层面对于前端框架的语法不支持,一般会需要在部署在生产环境前作一定的前端编译,这也是目前前端开发的标准做法。

针对这些需求,W3C标准化项目组,在2011年前后提出了WebComponents标准,现在由WhatWG进行维护。Web Components最终试图HTML、CSS和DOM API层面配合浏览器试图解决这些问题,是一种新的浏览器特性,同时也是一个复合的标准,提供了Web开发中组件的实现模型。

Web Components也是这篇文章的主角。

二、 标准细节

目前认为,Web Components是一组标准的集合。针对集合涵盖的内容,各个版本有不同的定义。由于篇幅所限,本文我们主要针对三个核心展开讲解,分别是Custom Elements、HTML template以及Shadow Dom。最新版本的浏览器还支持ES Modules,恰当的使用ES Modules,有利于模块的复用,在这种情况下,我们也可以把这个标准囊括进标准集合中。

2-1 Custom Elements

Custom Elements的出现,主要是为了解决HTML标签的有限性。它允许开发者自定义标签,并为其添加默认的行为、样式。

那么,如何来定义呢?下面是标准语法:

165f20b84c6d8954546880c56fd8ef73.png

这里是否传递第三个参数,决定了定义元素的类型。

如果增加了第三参数,则直接继承该HTML元素的行为,称为Customized built-in elements(自定义内置元素)。比如继承了HTMLImageElement,则继承了img标签元素的所有默认行为和样式。

如果缺省,该元素直接继承HTMLElement,称为Autonomous custom elements(自主自定义元素)。比如我们定义了一个user-card的标签,之后,我们就能直接使用<user-card></user-card>来引入这种标签的默认样式和行为。

我们首先来看一个自定义内置元素的例子:

28d79fb90c733b4aa16c9814fe3e3514.png

上述代码扩展了html默认的button元素,定义了一个hello-button组件。

这段代码有两个关键点:

1.CustomElements.define 需要指定第三个扩展参数。

2.使用时,使用is属性,来指定隶属的自定义元素名。

默认的,每个hello-button都会有button的所有属性,但增加了一点:点击会默认弹出“Hello!”。组件的示例依然可以定义事件,并且不会覆盖定义类上定义的事件。

需要说明的是,目前(2024年6月)safari浏览器最新版依然没有对自定义内置元素进行支持,Chrome、Edge、Firefox、Opera等都提供了支持。

接下来,我们再来看一下自主自定义元素。这个特性目前浏览器支持较好,主流的浏览器都已提供支持。

a378b4e78e8ebdb840efc7e39ca23410.png

之后我们在html里面加入:

7226a3a032a7d55461bf7cab745fae07.png

就可以显示了。这似乎有点像我们熟悉的React/Vue组件的用法了。

CustomElements支持生命周期的回调。

生命周期

说明

connectedCallback()

每当元素添加到文档中时调用。

disconnectedCallback()

每当元素从文档中移除时调用。

adoptedCallback()

每当元素被移动到新文档中时调用。

attributeChangedCallback()

在属性更改、添加、移除或替换时调用。

需配合静态的observedAttributes属性。

这里是一个在线的例子[4],读者可以尝试一下。

2-2 HTML template

上一节我们写的user-card组件,里面都是用dom方法动态创建的。这样不但麻烦,而且运行效率也偏低。为此,WebComponents标准提供了HTML templates的方式。

622295ec6cc527ab42042d72def8c3c5.png

<template>标签也可以多次复用。

尽管到这一步已经挺好了,但是元素仍旧不是很灵活。我们只能在里面显示一点文本,这里,可以使用 <slot> 插槽元素通过声明式的语法在每个元素实例中显示不同的文本。插槽由其 name 属性标识,并且允许开发者在模板中定义占位符,当在标记中使用该元素时,该占位符可以填充所需的任何 HTML 标记片段。

我们在上述代码的第18行增加下列代码:

b1c5aa4c6f70347b2b7551761fe6da7e.png

同时我们在调用时使用:

28e846924bab56918382aaa2ab4fc2f9.png

则完成了文字动态传入。

9667282ac6e22602ecf7ea136a3c0244.png

再进一步,我们索性支持外界传值支持一下。

76e93914a48f78795ae40f71697ea322.png

这样在调用时候,我们就可以用外界传递的图片了:

a6e4dfa9440132ec328c3a656a94d303.png

我们还可以在template标签里用<style>标签增加必要的样式。至此,我们基本上完成了这个自定义组件。这里是完整的代码[5]

之所以写在组件里,也就间接实现了封装。这样定义出的样式,理论上不会影响其他的元素。

这里:

4fb5843deb3802bd76c4e58d2250f276.png

伪类,选择包含使用这段 CSS 的 Shadow DOM 的影子宿主。具体到这个例子,我们的指的是这里:

8b2555d6ee8a0d28332b6dca1bd15987.png

为了最终实现封装,我们再来引出第三项技术:Shadow Dom。

2-3 Shadow Dom

自定义元素从定义上来说是一种可重用功能:它可以被放置在任何网页中,并且期望它能够正常工作。因此,很重要的一点是,运行在页面中的代码不应该能够通过修改自定义元素的内部实现而意外地破坏它。Shadow DOM允许你将一个 DOM 树附加到一个元素上,并且使该树的内部对于在页面中运行的 JavaScript 和 CSS 是隐藏的。

为了搞清Shadow DOM的机制,我们需要先厘清几个概念:

1.Shadow DOM: 是一种依附于文档原有节点的子 DOM,具有封装性。

2.Light DOM: 指原生的DOM节点,可以通过常规的API访问。Light DOM和Shadom DOM常常一起出现。这也是很有意思的一个比喻。一明一暗,灯下有影子。

3.Shadow Trees:Shadow DOM的树形结构。一般地,在Shadow Trees的节点不能直接被外部JavaScript的API和选择器访问到,但是浏览器会对这些节点做渲染。

4.Shadow Host:Shadow DOM所依附的DOM节点。

5.Shadow Root:Shadow Trees的根节点。外部JavaScript如果希望对Shadow Dom进行访问,通常会借助Shadow Root。

6.Shadow Boundary:Shadow Tree的边界,是JavaScript访问、CSS选择器访问的分界点。

7.content:指原本存在于Light DOM 结构中,被标签添加到影子 DOM 中的节点。自Chrome 53以后,content标签被弃用,转而使用template和slot标签。

8.distributed nodes:指原本位于Light DOM,但被content或template+slot添加到Shadow DOM 中的节点。

9.template:一致标签。类似我们经常用的<script type='tpl'>,它不会被解析为dom树的一部分,template的内容可以被塞入到Shadow DOM中并且反复利用,在template中可以设置style,但只对这个template中的元素有效。

10.slot:与template合用的标签,用于在template中预留显示坑位。

下面这幅图,显示了这些概念之间的关系:

7e65ae86c1250124bbce05b7f03a1a94.png

了解了Shadow DOM的概念,我们就可以利用Shadow Dom做一些事情了。de649d72083cf6206d8c16f670f1554f.png

这里注意下{mode: 'open'},此后通过div.shadowRoot即可拿到sr的实例。sr可以使用一般的JavaScript API来做相关的操作。

如果这里采用{mode: 'closed'},则此时div.shadowRoot为null。外部不可能再拿到sr的实例。此时外部很难操作到sr下的Shadow DOM,仅可以依靠Shadow内部的元素来进行操作。

下面是操作Shadow DOM样式的几种方法:

1.在Shadow DOM内部来操作Shadow Host的样式。

:host 允许你选择并样式化 Shadow Tree所寄宿的元素

576ffe54f0477f0659a04fd5c7d7b1a7.png

2.跨越Shadow Boundary的样式::part()

对于::part,在允许样式定义的Shadow DOM,给属性part赋值,样式选择器可以使用::part(属性值)即可实现指定样式,这与之前不同的是,Shadow Dom元素知道外界可能会对其某些元素进行变化,是可以控制变化范围的。需要注意的是,在::part()选择器后,子代选择器无效。如你不能使用::part(foo) span。

24c296b0963a514bf4e3beef4205bb02.png 

::part()选择器自Chrome73开始支持。之前的版本,可以考虑^和^^选择器,^和^^选择Shadow DOM在最新版本已经无效。

三、 与现代前端框架的关系

从之前的内容我们可以看到,Web Components标准中有若干内容与现代前端框架有异曲同工的感觉。同时,现代前端框架在设计时或多或少会参考Web Components的标准。VueJS的创始人尤雨溪曾明确表示过Vue的模版设计部分遵照了Web Components的标准。这也为以后浏览器能力逐渐增强,前端框架减负,提供了可能。

同时,现在大多数的前端框架都提供了和Web Components组件共存的机制。以Vue为例,官方更是提供了将Vue组件编译为Web Components自主自定元素方案和自主自定元素转化为Vue组件的工具链。

直接用Web Components标准撰写的组件,原则上不需要经过预编译环节,可以直接运行于浏览器,理论上会比其他前端框架性能有一定的优势。但是,由于该标准提供的API较原始,需要做进一步封装才能更好的使用。同时,标准缺乏对现今流行的MVVM的支持,使得前端框架在数据驱动开发模式上仍有用武之地。

Shadow Dom等标准的进展,客观上也使得前端微服务模式慢慢成型,使得qiankun等前端解决方案有了落地的基石。

四、 结语

本文我们介绍了Web Components标准的主要技术点。应该注意到的是,标准还在不断演化过程中,各家浏览器的支持也在不断完善。我们期待,不久的将来,藉由浏览器原生支持的组件化方案,能够大放光彩。

文内链接

[1].https://github.com/taisuke-j/progress-ring-component

[2].https://docs.microsoft.com/en-us/previous-versions/aa918246(v=msdn.10)

[3].https://www.slideshare.net/slideshow/xml-binding-language-20/155196#5

[4].https://jsbin.com/qorohov/8/edit?html,js,console,output

[5]. https://jsbin.com/qorohov/23/edit?html,output

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[电子电路学]电路分析基本概念1

第一章 电路分析的基本概念和基本定律 电路模型 反映实际电路部件的主要电磁性质的理想电路元件及其组合&#xff0c;是实际电路电气特性的抽象和近似。 理想电路元件 实际电路器件品种繁多&#xff0c;其电磁特性多元而复杂&#xff0c;分析和计算时非常困难。而理想电路元件…

240627_关于CNN中图像维度变化问题

240627_关于CNN中图像维度变化问题 在学习一些经典模型时&#xff0c;其中得维度变化关系总搞不太明白&#xff0c;集中学习了以下&#xff0c;在此作以梳理总结&#xff1a; 一般来说涉及到的维度变换都是四个维度&#xff0c;当batch size4&#xff0c;图像尺寸为640*640&a…

正点原子 iwdg wwdg timr

这个iwdg 的超时时间的计算公式 ———————————————— wwdg 超时时间的计算公式 4096是stm32固定死的 wwdg的时钟频率是36mhz&#xff0c;因为apb1分频2得到wwdg的时钟频率&#xff0c;这个是stm32自己就这样做的 看cubemx的时钟图也看得出来 iwdg和wwdg的区分 ti…

[Java基础揉碎]反射

目录 引出反射机制​编辑 介绍反射机制​编辑 反射的优点和缺点 (反射调用优化 )​编辑 Class类 class常用方法 ​编辑 ​编辑 获取class类对象的不同方式 哪些类型有class对象 ​编辑 类加载 ​编辑类加载流程图 类加载的五个阶段 ​编辑 通过反射获取类的结构信…

合芯科技冯春阳博士受邀出席苏州大学技术分享会

近日&#xff0c;苏州大学电子信息学院与合芯科技苏州公司成功举办“新时代与‘芯’相遇&#xff0c;科技赋能向未来”的技术分享会。合芯科技冯春阳博士进行了主题为“高性能CPU关键技术与发展现状”的专题分享&#xff0c;并参加导师聘请仪式。苏州大学电子信息学院党委副书记…

【ONLYOFFICE 8.1】的安装与使用——功能全面的 PDF 编辑器、幻灯片版式、优化电子表格的协作

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、ONLYOFFICE 简介三、安装1. Windows/Mac 安装2. 文档开发者版安装安装前准备使用 Docker 安装使用 Linux 发行版安装配置 ONLYOFFICE 文档开发者版集成和开发 四、使用1. 功能全面的 PDF 编辑器PDF 查看和导航P…

如何做好新闻软文宣发媒体资源筛选?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 新闻软文宣发是指企业通过创造或利用新闻事件&#xff0c…

使用systemd管理Linux下的frps服务:安装、配置及自动化操作指南

在 Linux 系统下&#xff0c;使用 systemd 可以方便地控制 frps 服务端的启动、停止、配置后台运行以及开机自启动。以下是具体的操作步骤&#xff1a; 1. 安装 systemd 如果您的 Linux 服务器上尚未安装 systemd&#xff0c;可以使用包管理器如 yum&#xff08;适用于 Cent…

stm32 No traget connected/debug识别不到串口的问题

关于stm32串口识别不到&#xff0c;第一步先确定是否线接错&#xff08;stlink与stm32接口对应&#xff09;&#xff0c;如果确认接线没有问题的话&#xff0c;可以使用以下方法&#xff0c;成功率较高。 首先将stlink的boot0置1&#xff0c;就是把跳线帽换到高电平这一侧&…

[数据集][目标检测]游泳者溺水检测数据集VOC+YOLO格式4599张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4599 标注数量(xml文件个数)&#xff1a;4599 标注数量(txt文件个数)&#xff1a;4599 标注…

编写一个基于其他系的linux系统并且把它打包为一个iso镜像思想

目录 前面写的一篇文章 前言 isolinux引导模式启动流程 为什么要initramdisk操作而不直接加载文件系统 编写系统的思想 可能问题 一般的iso镜像目前只支持最大4G的大小&#xff0c;需要怎么解决&#xff1f; 如何去找驱动 木木em哈哈想说的话&#xff08;与本博文无光&…

详细分析SpringBootTest中的测试类(附Demo)

目录 前言1. 基本知识2. Demo3. 实战3.1 项目测试3.2 功能测试 前言 书写测试类&#xff0c;一般只需要加入Test即可&#xff0c;但是结合Springboot项目来整体测试对应需要怎么下手 详细的Java知识点推荐阅读&#xff1a;java框架 零基础从入门到精通的学习路线 附开源项目面…

[CAN] 通讯协议手动解析与手动打包 [手撕编码格式]

手动解析与手动打包 一、Intel格式编码1.1 报文解析。1.2 报文打包二、Motorola格式通讯协议2.1 报文解析。2.2 报文打包🙋 前言 CAN有两种编码格式:Intel编码格式 和 Motorola编码格式,本教程将分别对两种格式进行手动解析与手动打包。 一、Intel格式编码 假设已知雷达CAN…

【C++题解】1721. 输出个位为5或者个位为8数

问题&#xff1a;1721. 输出个位为5或者个位为8数 类型&#xff1a;简单循环 题目描述&#xff1a; 请从小到大输出 1∼n 中所有个位为 5 或者个位为8 的所有的整数&#xff0c;每行 1 个。 比如&#xff0c;假设 n20&#xff0c;那么满足条件的数输出如下&#xff1a; 5 8 1…

【多线程】如何解决线程安全问题?

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. synchronized 关键字1.1 锁是什么1.2 如何加锁1.3 synchronized 修饰方法1) 修饰普通成员方法2) 修饰静态…

Rust 程序设计语言学习——泛型、Trait和生命周期

每一种编程语言都有高效处理重复概念的工具。在 Rust 中其工具之一就是泛型。泛型是具体类型或其他属性的抽象替代。 Trait 定义了某个特定类型拥有可能与其他类型共享的功能。可以通过 Trait 以一种抽象的方式定义共同行为。可以使用 trait bounds 指定泛型是任何拥有特定行为…

Java——IO流(一)-(8/8):释放资源-try-catch-finally、try-catch-resource

目录 try-catch-finally 介绍 实例演示1 实例演示2 try-catch-resource 介绍 实例演示 try-catch-finally 介绍 普通的释放流的方法可能会因中间的异常或是其他原因&#xff0c;导致程序执行不到释放流的代码就结束了&#xff0c;会有资源浪费的风险&#xff0c;所以建…

入门JavaWeb之 JavaBean 实体类

JavaBean 有特定写法&#xff1a; 1.必须有一个无参构造 2.属性必须私有 3.必须有对应的 get/set 方法 一般用来和数据库的字段做映射 ORM&#xff1a;对象关系映射 表->类 字段->属性 行记录->对象 连接数据库 没有的话去 Settings -> Plugins 搜索 Data…

JavaScript--js基础(详细 全面)

目录 前言: JavaScript 是什么&#xff1f;JavaScript 简介 1.JavaScript历史 2.JavaScript 具有以下特点 第一个JavaScript程序 1.在脚本文件中编写JavaScript代码 2.JavaScript代码执行顺序 基本语法 1.变量 2.数据类型 3.算术运算符 4.赋值运算 5.字符串运算符 6…

GoSync+华为智能穿戴使用指导

GoSync官方简介&#xff1a; GoSync 是一款免费应用程序&#xff0c;主要用于将您的可穿戴设备中的步行、跑步、骑自行车和游泳等活动数据同步到您的 Google Fit 和其他健身平台。在开始同步数据之前&#xff0c;您需要将您的可穿戴设备账户与您的健身平台账户连接起来。在创建…