当前位置: 首页 > article >正文

关于Web Component

2024年8月14日

引言

Web Component 是一种用于构建可复用用户界面组件的技术,开发者可以创建自定义的 HTML 标签,并将其封装为包含逻辑和样式的独立组件,从而在任何 Web 应用中重复使用,并且可以做到无框架跨框架。

不同于 Vue/React 等社区或厂商的组件化开发方案,Web Component 被定义在标准的 HTML 和 DOM 标准中。它由一组相关的 Web 平台 API 组成,也可以与现有的前端框架和库配合使用Web Component 的兼容性良好,可以在现代浏览器中直接使用,也可以通过 polyfill 兼容到旧版浏览器。

每个 Web Component 都具有自己的 DOM 和样式隔离,避免了全局 CSS 和 JavaScript 的冲突问题。它还支持自定义事件和属性,可以与其他组件进行通信和交互。实现这些主要基于其三个技术:

  • Custom elements:一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
  • Shadow DOM:一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突
  • HTML templates:<template> 和 <slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

如何简单创建一个Web Components

挂载

首先为这个项目创建一个文件夹,然后在里面为组件准备一个button.js文件,在这里将编写一个按钮组件,button.js文件内容如下:

  1. 模版
let templateTemp = `
<template id='button'>
    <div class="button">按钮</div>
</template>
`;
  1. 样式
let styleTemp = `
.button{
    width:70px;
    height:50px;
    background-color:rgb(54, 54, 252);
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 10px;
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    cursor: pointer;
}
.button:hover{
    background-color:rgb(38, 38, 250);
}
.button:active{
    background-color:rgb(5, 5, 255);
}`;
  1. 将模版字符串转化为document节点
const parser = new DOMParser();
const doc = parser.parseFromString(templateTemp, "text/html");
const temp = doc.getElementById("button");
  1. 创建自定义组件
class button extends HTMLElement {
  constructor() {
    super();
    //创建一个影子节点,组件会挂载在上面,参数mode表示是否可被外部访问
    const shadow = this.attachShadow({ mode: "open" });
    
    //获取模版和样式
    const content = temp.content.cloneNode(true);

    const style = document.createElement("style");
    style.textContent = styleTemp;

    //挂载
    shadow.appendChild(style);
    shadow.append(content);
  }
}
customElements.define("zf-button", button);
  1. 接下来查看这个组件,比如在一个原生的index.html文件中
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="icon" type="svg+xml" href="public/logo.svg">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My HTML File</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="script.js"></script>
    //导入文件
    <script src="button.js"></script>
</head>
<body>
    //直接使用模版
    <zf-button></zf-button>
</body>
</html>

这样一个简单的Web Component就挂载好了并且可以看到了。
在这里插入图片描述
现在这个按钮已经有最基本的样式,但相比Element组件库的按钮还不够丰富,比如按钮的类型,或大或小的,在用这个组件时可以以参数的方式进行切换,还有颜色等等,这些就涉及如何与组件通讯了,还有想让按钮有个图标,这样就要用到插槽。在处理这些问题前,先来了解Web Component的生命周期。


生命周期

一个Web Component有4个生命周期

  1. connectedCallback
    首次插入文档DOM时调用,这个回调函数通常用于执行一些初始化操作,比如添加事件监听器、请求数据等等。在这个时候,元素已经被添加到了文档中,可以访问到this.shadowRoot里的 DOM 和其他元素。
  2. disconnectedCallback
    从文档删除时调用,这个回调函数通常用于清理一些资源,比如取消事件监听器、停止定时器等等。在这个时候,元素已经不再被文档所包含,无法访问到 DOM 和其他元素。
  3. adoptedCallback
    移动到新文档时调用,这个回调函数通常用于处理一些文档级别的操作,比如重新计算布局(重排)、修改样式等等。在这个时候,元素已经从原来的文档中移除,并被添加到了新的文档中。
  4. attributeChangedCallback
    修改自身属性时调用,这个回调函数通常用于处理一些属性相关的逻辑,比如根据属性值的变化更新元素的样式、重新渲染元素等等。在这个时候,元素的属性已经被修改,可以通过新的属性值来进行相应的处理。
class button extends HTMLElement {
  constructor() {
    super();
  }
  connectedCallback() {
    console.log("首次插入文档");
  }
  disconnectedCallback() {
    console.log("从文档删除");
  }
  adoptedCallback() {
    console.log("移动到新文档");
  }
  attributeChangedCallback() {
    console.log("修改");
  }
}

组件通讯

组件通讯主要就是外部传递信息给组件内部和组件内部传递信息给外部。主要的实现在于shadowRoot的方法去操作组件的自定义属性。比如想要修改刚才按钮组件的文字,那么给组件添加自定义属性text:

<zf-button text="添加"></zf-button>

然后在生命周期connectedCallback中获取并赋值

connectedCallback() {
    if (this.hasAttribute("text")) {
      this.shadowRoot.querySelector(".button").innerHTML =
        this.getAttribute("text");
    }
}

再或者想要点击这个按钮后,文字变为修改,这个就得在生命周期attributeChangedCallback去监听text属性,如果有huan hu。
首先要添加observedAttributes数组,元素为自定义属性的名字,这样attributeChangedCallback才能监听。

static observedAttributes = ["text"];

接着在attributeChangedCallback,监听到text的变化,然后在shadowRoot中找到按钮组件进行修改。

attributeChangedCallback(name, oldValue, newValue) {
    if (name === "text") {
      this.shadowRoot.querySelector(".button").innerHTML =newValue;
    }
}

最后就是外部如何去修改组件的自定义属性,这里需要shadow节点可以被访问

const shadow = this.attachShadow({ mode: "open" });

然后给组件添加点击事件,在里面修改组件的属性值,这样的修改会被组件的attributeChangedCallback函数捕抓。

document.addEventListener("DOMContentLoaded", function () {
  document.querySelector("#btn").addEventListener("click", function () {
    document.querySelector("#btn").attributes.text.value = "修改";
  });
});

用Web Component构建组件库

这样的组件库相比针对Vue的element和针对react的vant,它不会受框架的限制,就是不能享受语言框架带来的便利。比如Vue的响应式属性和事件绑定,在原生的html不具备,然后其组件库也是不能使用的,只能用原生的方法去实现。这样的组件库我找到了:

Quark Design
https://quark-ecosystem.github.io/quarkd-docs/vue/#/

还有一些框架可以自己去搭建Web Component组件库,比如Omi框架,在这里用Web Component搭建的组件库,可以适配vue等语言系统的特性

OMI Web Components
https://omi.cdn-go.cn/home/latest/zh/


http://www.kler.cn/a/402155.html

相关文章:

  • 基于YOLOv8深度学习的智慧交通事故评级检测系统研究与实现(PyQt5界面+数据集+训练代码)
  • 2022 年 9 月青少年软编等考 C 语言二级真题解析
  • ubuntu下怎么设置机器程序开机自启?
  • 完整http服务器
  • 前后端学习
  • 量化交易系统开发-实时行情自动化交易-4.1.3.A股平均趋向指数(ADX)实现
  • 前端面试笔试(四)
  • 使用Go语言编写一个Web服务器,处理客户端的HTTP请求,并返回相应的HTML页面。
  • 百度AI人脸检测与对比
  • 优选算法--快乐数(快慢指针)循环链表
  • 《物理学进展》
  • koa-body 的详细使用文档
  • Node.js 版本管理的最终答案 Volta
  • windows系统中实现对于appium的依赖搭建
  • Android CALL按键同步切换通话界面上免提和听筒的图标显示
  • Linux进阶:用户、用户组、权限
  • Vue实现响应式导航菜单:桌面端导航栏 + 移动端抽屉式菜单
  • HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)习惯推荐方案概述
  • 批量将当前目录里的所有pdf 转化为png 格式
  • 鸿蒙实战:使用显式Want启动Ability
  • 【C++课程学习】:继承:默认成员函数
  • DBSCAN聚类——基于密度的聚类算法(常用的聚类算法)
  • HarmonyOS4+NEXT星河版入门与项目实战-------- Text 组件与国际化实现
  • 魔乐社区平台下载书生模型
  • DNS协议详解:原理、查询过程及常见问题
  • How to install rust in Ubuntu 24.04