一文读懂Web Component

news2024/11/20 12:37:23

前言

由于最近作者在学习微前端,web component也是其中一大特性,部分微前端框架使用到,也是深入学习了一下相关的知识,分享出来。

Web Component是什么?

Web Component 实际上一系列技术的组合,主要包含 3 部分:

  • 自定义元素。 在 HTML 基础标签外扩展自定义标签元素,也就是我们平时使用框架的"组件";
  • Shadow DOM。 主要用于将 Shadow DOM 的内容与外层 document DOM 隔离,可以理解为在document中的一个子容器,放置各种组件;
  • HTML 模板。 使用 <template> 来定义组件模板,使用 <slot> 作为插槽使用(Vuer一定不陌生);

在一份html文件中的一个web component看起来是这样的:

<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
  <div slot="slot-ele">插槽内容</div>
</trace-ele>

看起来很像Vue吧?接下来让我们一个个demo学习web component

上手

由于Web Component亲和原生,因此无需其他包的依赖,一个index.html和一个index.js即可体验学习。

我们直接写一个html模板,文章的案例组件统称为<trace-ele />

index.html:

<body>
 <template id="trace">
      <div class="container">
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        />
        <p class="title">学习Web Component</p>
        <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
        <p class="price">¥25.00</p>
      </div>
    </template>
    <trace-ele />
    <script src="./index.js" />
</body>

这里我们写了一个"模板"——template,并在下面声明了<trace-ele />组件。

而实现这一切的原理在index.js中。

class Trace extends HTMLElement {
  constructor() {
    super();
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    this.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

Web Component组件本质是一个类继承于HTMLElement,当customElements.define声明完组件后,类中的this指向于组件本身,打印结果如下:

image.png

在初始化时,需要提供给组件一个空壳,并且绑定template元素的id,这样就出现组件效果了。

image.png

看到这里是不是感觉和Vue很像呢?接下来我们继续升级组件的功能~

来点样式吧

在上一节基础上,给组件上点样式,很简单,改变index.html即可,在template中加入style

<body>
 <template id="trace">
      <div class="container">
        <img
          class="image"
          src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
          alt=""
        />
        <p class="title">学习Web Component</p>
        <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
        <p class="price">¥25.00</p>
      </div>
      
      <style>
        .container {
          display: inline-flex;
          flex-direction: column;
          border-radius: 6px;
          border: 1px solid silver;
          padding: 16px;
          margin-right: 16px;
        }
        .image {
          border-radius: 6px;
        }
        .title {
          font-weight: 500;
          font-size: 16px;
          line-height: 22px;
          color: #222;
          margin-top: 14px;
          margin-bottom: 9px;
        }
        .desc {
          margin-bottom: 12px;
          line-height: 1;
          font-size: 14px;
        }
        .price {
          font-size: 14px;
        }
      </style>
    </template>
    <trace-ele />
    <script src="./index.js" />
</body>

样式生效:

image.png

但是这里如果给一个通用标签的样式,就像这样:

<body>
    <p>组件外的P标签</p>
        <template>
        <p>组件中的P标签</p>
        <style>
           p {
             color: red;
           }
            ...
            .container {}
        </style>
        </template>
</body>

效果如下:

image.png

可以看到组件外的p标签也被影响了,颜色变为红色,而在组件概念中这个样式其实只期望作用于组件本身。这也是样式隔离的概念,而很幸运,Web Component提供了开箱即用的样式隔离方案。

为了不让 <template> 里的 <style> CSS 和全局的 CSS 有冲突,我们可以将组件挂在到 Shadow Root 上,再用 Shadow Root 挂到外层的 document DOM 上,这样就可以实现 CSS 的隔离啦:

class Trace extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
    
    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

从控制台中观察:

image.png

而如果有多个组件本质其实就是在document中有多个Shadow Root

整个DOM架构图是这样的:

image.png

Shadow DOM 的一大优点是能将 DOM 结构、样式、行为与 Document DOM 隔离开,非常适合做组件的封装,因此它能成为 Web Component 的重要组成部分之一。

Props

VueReact一样,Web Component也提供了父传子的形式。

index.html:

<trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">

这里传了3个props给组件,在组件中打印this如下:

火眼金睛的我已经找到了在组件中接受传参的入口:

image.png

做一个简单的动态赋值:

class Trace extends HTMLElement {
  constructor() {
    super();

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

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle.querySelector('.container > .title').textContent = this.getAttribute('name');
    cloneEle.querySelector('.container > .price').textContent = this.getAttribute('version');
    cloneEle.querySelector('.container > .desc').textContent = this.getAttribute('desc');

    this.shadowRoot.appendChild(cloneEle);
  }
}

customElements.define("trace-ele", Trace);

搞定~

Slot

HTML 模板的另一个好处是可以像 Vue 一样使用 <slot>。比如,现在我们可以在这个 <trace-ele> 最下面添加一个插槽:

<body>
    <template id="trace">
        <div class="container">
            <p>组件中的P标签</p>
            <img
              class="image"
              src="https://pic1.zhimg.com/50/v2-a6d65e05ec8db74369f3a7c0073a227a_200x0.webp"
              alt=""
            />
            <p class="title">学习Web Component</p>
            <p class="desc">Web Component是微前端沙盒隔离原理的重要知识</p>
            <p class="price">¥25.00</p>
            <slot name="slot-ele"></slot>
        </div>
        <style>
        ...
        </style>
    </template>
    <trace-ele name="webComponent" version="0.0.1" desc="原生态自带隔离的组件">
        <div slot="slot-ele">插槽内容</div>
    </trace-ele>
</body>

这样我们就可以实现自定义插槽内容了。

事件绑定

Web Component也可以给组件中元素或者插槽绑定事件。

class Trace extends HTMLElement {
  constructor() {
    super();

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

    const templateEle = document.getElementById("trace");
    const cloneEle = templateEle.content.cloneNode(true);
    cloneEle
      .querySelector(".container > .title")
      .addEventListener("click", this.onClick);

    this.shadowRoot.appendChild(cloneEle);
  }

  onClick = () => {
    alert("Click Me!");
  };
}

customElements.define("trace-ele", Trace);

image.png

总结

上面主要给大家分享了一下 Web Component 的一些使用方法。总的来说,Web Component 是一系列 API 的组合:

  • Custom Element:注册和使用组件
  • Shadow DOM:隔离 CSS
  • HTML template 和 slot:灵活的 DOM 结构

它看起来仿佛是现在主流框架的基建实现,框架也正是基于原生的能力实现出一整套的解决方案,就比如Vue的响应式以来追踪、模板语法数据绑定,都是我们希望看到的。

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

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

相关文章

【Java】Enum 枚举

java 中的枚举类型本质是默认继承于 java.lang.Enum 的类 常用方法 方法签名描述values()以数组形式返回枚举类型的所有成员ordinal()获取枚举成员的索引位置&#xff08;编号、序号&#xff09;valueOf()将普通字符串转换为枚举实例compareTo()比较两个枚举成员在定义是的顺…

名称空间(namespaces)与作用域

引入 在python解释器中运行一行代码import this就可以看到“传说”中的python之禅&#xff0c;它体现了使用python进行开发的规范&#xff0c;而最后一句 - Namespaces are one honking great idea -- lets do more of those!就是本文的主角。 名称空间(Namespaces) 名称空间…

PointNet:利用深度学习对点云进行3D分类和语义分割

PointNet&#xff1a;利用深度学习对点云进行3D分类和语义分割 参考自&#xff0c;PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation 代码仓库地址为&#xff1a;https://github.com/charlesq34/pointnet/ 介绍 这次介绍的是一个比较基础的工作…

部署博客系统(部署博客系统到云服务器)

目录 1、建库建表 2、微调本地代码 3、打包&#xff08;使用Maven打成war包&#xff09; 4、拷贝到Tomcat的webapps 5、启动Tomcat服务器&#xff08;只有启动成功了才能进行访问&#xff09; 6、访问博客系统 1、建库建表 云服务器访问的是云服务器上的数据库,不是…

FFmpeg YUV 编码 H264

1. x264 库 由于 FFmpeg 不支持 h264 编码,所以需要集成 x264 库,现在使用的是当前最新版本 1.1 官方下载地址: videolanhttps://www.videolan.org/developers/x264.html 1.2 编译脚本地址: x264-ioshttps://github.com/kewlbear/x264-

【信息系统项目管理师】概要和框架-2023年5月7日总结

还有20天考试&#xff0c;记录下这二十天的学习内容。 今天之前4月4日到4月13日五天修炼看了一半&#xff0c;看到了项目风险管理&#xff0c;云里雾里看了个大概。 听野人老师的课从第一章跟着到了第十章&#xff0c;听一会儿就走神&#xff0c;听一会儿就走神。 改变思路&…

1.4 初探Spring - 采用Java配置类管理Bean

一、采用Java配置类管理Bean 1、打开项目 Maven项目 - SpringDemo 2、创建子包 在net.hf.spring包里创建day04子包 3、创建杀龙任务类 在day04子包里创建杀龙任务类 - SlayDragonQuest package net.hf.spring.day04;/*** 功能&#xff1a;杀龙任务类* 作者&#xff1…

Ubuntu搭建VPN服务

PPTD协议 此协议据说安全级别不高&#xff0c;苹果系统已经不支持&#xff0c;但windows依然支持 1.安装,root账号登录服务器 apt-get update apt-get install pptpd 2.配置主机ip及连接主机的设备所分配ip池,客户端分配的内网ip段。 vim /etc/pptpd.conf 将以下两行注释去…

同云跨可用区备份容灾解决方案详解

云可用区 云可用区&#xff08;Availability Zone,AZ&#xff09;是一个可用区是一个或多个物理数据中心的集合&#xff0c;有独立的风火水电&#xff0c;可用区内逻辑上再将计算、网络、存储等资源划分成多个集群。一个地域中的多个可用区间通过高速光纤相连&#xff0c;以满足…

Ubuntu安装Mininet和Ryu出现的问题

问题1-Ryu: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host‘pypi.org’, port443): 解决&#xff1a; pip install XXX -i http://pypi.douban.com/simple --trusted-host pypi.douban.com或 pip install XXX -i http://mirrors.aliyun.c…

国内首个BIM全生命周期装配式建筑项目,建设仅用25周

hi大家好&#xff0c;这里是建模助手。 文章开头我想先问问各位&#xff0c;在你眼中&#xff0c;25周能干点什么&#xff01;小编和你说&#xff0c;在建筑行业里的25周&#xff0c;可以完成一整个保障房项目的建设。 我没开玩笑... 4月16日下午&#xff0c;随着最后一个混凝土…

信号与槽机制

一、信号与槽 1、什么是信号与槽&#xff1f; 信号和槽是用于对象之间的通信&#xff0c;它是Qt的核心机制&#xff0c;在Qt编程中有着广泛的应用。如果想学好Qt&#xff0c;一定要充分掌握信号的槽的概念与使用。 2、信号和槽的代码实例 在Qt中&#xff0c;发送对象、发送的信…

美国纽扣电池的包装电池盒必须附带警告标签16 CFR 第 1700.20

美国纽扣电池及硬币电池的包装、电池盒必须附带警告标签16 CFR 第 1700.20 美国要求在纽扣电池或硬币电池的包装上、电池盒上以及包含纽扣电池或硬币电池的消费品附带说明和手册上贴上警告标签。 商品法规、标准和要求纽扣电池和硬币电池以下所有项&#xff1a; 16 CFR 第 17…

虚幻引擎配置物体水面浮力的简便方法

虚幻引擎配置物体水面浮力的简便方法 目录 虚幻引擎配置物体水面浮力的简便方法前言前期工作配置水面浮力针对一个立方体的水面浮力配置针对船3D模型的水面浮力配置 小结 前言 在使用虚幻引擎配置导入的3D模型时&#xff0c;如何快速地将水面浮力配置正确&#xff0c;从而使得…

快速原型设计工具(Axure)的简单使用

1.运行 安装好后运行&#xff0c;可以看到欢迎界面(不想每次启动都弹出这个的话建议勾选启动时不显示) ​ 这就是Axure的主要界面了&#xff0c;能成功进到这里就说明安装成功&#xff01; 2.Axure主要界面 3.展示形式 通过Axure这个软件生成和打开的文件的后缀名是 .rp&#x…

如何在Jetpack Compose中将可滚动项捕捉到屏幕中心

如何在Jetpack Compose中将可滚动项捕捉到屏幕中心 从 Snapper 迁移到 SnapFlingBehavior 之前&#xff0c;我们探讨了Android应用程序开发中一个常见的用例&#xff1a;在fling手势后将可滚动项捕捉到屏幕中心。 为了在Jetpack Compose中实现这一目标&#xff0c;我们使用…

手把手教你写Web自动化测试并生成美观交互的测试报告

B站首推&#xff01;2023最详细自动化测试合集&#xff0c;小白皆可掌握&#xff0c;让测试变得简单、快捷、可靠https://www.bilibili.com/video/BV1ua4y1V7Db 目录 摘要&#xff1a; Web自动化测试 Allure测试报告 总结 摘要&#xff1a; 在Web应用程序开发中&#xff0c…

ICV: 全球QRNG产业规模在2030年有望突破200亿美元

近日&#xff0c;专注于前沿科技领域的国际咨询机构ICV发布了《全球量子随机数发生器的产业研究报告》&#xff0c;从多个角度对QRNG的市场进行预测。 QRNG 是解决与随机数相关的问题&#xff08;例如密码解决方案&#xff09;的重要硬件来源。 QRNG 是随着量子物理技术的发展…

DJ4-4 基本分页存储管理方式

目录 离散分配的基本概念 4.4.1 分页存储管理基本思想 1、分页存储管理的基本方法 2、页面与物理块 3、实现分页存储管理的数据结构 4、实现分页存储管理的地址结构 5、分页存储管理的逻辑地址表示 4.4.2 地址变换机构 1、基本的地址变换机构 2、具有快表的地址变换…

Alibaba技术官熬夜肝出的,Kafka “限量笔记” 牛掰 ~

前言 分布式&#xff0c;是程序员必备技能之一&#xff0c;在面试过程中属于必备类的&#xff0c;在工作中更是会经常用到。而Kafka是一个分布式的基于发布订阅的消息队列&#xff0c;目前它的魅力是无穷的&#xff0c;对于Kafka的奥秘&#xff0c;还需要我们细细去探寻。 要…