web component - 使用HTML Templates和Shadow DOM构建现代UI组件

Web Component是一种用于构建可重用的UI组件的技术。它使用标准化的浏览器API,包括Custom Elements、Shadow DOM和HTML Templates来实现组件化开发方式。这些API都是现代浏览器原生支持的,因此不需要引入第三方库或框架即可使用。

在这篇博客中,我们将介绍如何使用Web Component技术构建一个名为UserCard的UI组件。这个组件可以显示用户的头像、姓名和电子邮件地址,并提供一个关注按钮。当用户点击关注按钮时,组件会触发一个自定义事件,允许开发者处理按钮点击事件。

在线例子和源码点击我

首先,让我们来看看这个组件的代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 使用template写模板 --><template id="card-template"><div class="user-card-container"><img /><div class="content"><div class="name"></div><div class="email"></div><button class="follow-btn"></button></div></div></template><user-cardid="user-card-id"userId="1"image="https://semantic-ui.com/images/avatar2/large/kristy.png"name="User Name"email="yourMail@some-email.com"hasFollow="false"handleFollowEvent="handleFollowEvent"></user-card><script src="./user-card.js"></script><script>const userCard = document.getElementById('user-card-id')/** 监听组件事件 */userCard.addEventListener('follow-event', (e) => {const functionName = e.detail.methodthis[functionName] && this[functionName](e.detail.data)})/** 修改按钮状态  */function handleFollowEvent(data) {userCard.setAttribute('hasFollow', userCard.getAttribute('hasFollow') === 'true' ? 'false' : 'true')}</script>
</body>
</html>
class UserCard extends HTMLElement {constructor() {super();this.shadow = this.attachShadow({ mode: "open" });}/** 内容挂载时候回调 */connectedCallback() {this.render();}/** 指定监听的属性列表 */static get observedAttributes() {return ["hasfollow"];}/** 监听属性变化 */attributeChangedCallback(name, newValue, oldValue) {// 加上newValue判断是防止第一次传属性就执行了if (newValue && newValue !== oldValue) {this.processDomRender();}}/** 具体的渲染函数 */render() {const link = document.createElement("link");link.rel = "stylesheet";link.href = "./user-card.css";// css加载完才开始渲染内容,避免页面错乱问题link.onload = () => {// 把模板内容挂在上shadow domthis.processDomRender();};this.shadowRoot.appendChild(link);}/** 仅render dom */processDomRender() {const userCardContainer = this.shadowRoot.querySelector(".user-card-container");userCardContainer && this.shadowRoot.removeChild(userCardContainer);this.shadowRoot.appendChild(this.getContent());this.setContent();}/** 获取模板 */getContent() {const template = document.getElementById("card-template");// 拷贝模板,但是不改动模板的内容const content = template.content.cloneNode(true);return content;}/** 把组件传下来的属性挂载到shadow dom上 */setContent() {this.shadowRoot.querySelector("img").setAttribute("src", this.getAttribute("image"));this.shadowRoot.querySelector(".name").innerHTML =this.getAttribute("name");this.shadowRoot.querySelector(".email").innerHTML =this.getAttribute("email");this.shadowRoot.querySelector(".follow-btn").innerHTML =this.getAttribute("hasFollow") === "true" ? "已关注" : " 关注";// 按钮点击事件this.shadowRoot.querySelector(".follow-btn").addEventListener("click", () => {const event = new CustomEvent("follow-event", {detail: {method: this.getAttribute("handleFollowEvent"),data: {id: this.getAttribute("userId"),},},});this.dispatchEvent(event);});}
}customElements.define("user-card", UserCard);
.user-card-container {height: 120px;display: flex;background-color: #d4d4d4;border: 1px solid #d5d5d5;box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);border-radius: 3px;overflow: hidden;padding: 10px;box-sizing: border-box;
}.user-card-container img {height: 100px;width: 100px;
}.user-card-container .content {margin: 10px;flex: 1;display: flex;flex-direction: column;
}.user-card-container .content .name {font-size: 20px;font-weight: 600;line-height: 1;margin: 0;margin-bottom: 5px;
}
.user-card-container .content .email {padding: 5px 0;font-size: 12px;opacity: 0.75;line-height: 1;margin: 0;margin-bottom: 15px;
}
.user-card-container .content .follow-btn {width: 100px;font-size: 12px;border-radius: 5px;text-transform: uppercase;
}

这个组件使用了三个Web Component的API:Custom Elements、Shadow DOM和HTML Templates。Custom Elements用于定义一个自定义元素UserCard,Shadow DOM用于封装组件内部的样式和结构,防止外部样式干扰组件,HTML Templates则用于定义组件的模板。

在构造函数中,我们使用attachShadow方法创建了一个shadowRoot,并将其挂载到自定义元素上。接着,在connectedCallback方法中,我们调用了render方法来渲染组件。

在render方法中,我们首先将组件的CSS样式引入到shadowRoot中。接着,我们调用processDomRender方法来渲染组件的结构和内容。

在processDomRender方法中,我们首先使用querySelector方法查找user-card-container元素是否已经存在,如果存在,则将其从shadowRoot中删除。接着,我们调用getContent方法获取组件的模板,并将其添加到shadowRoot中。最后,我们调用setContent方法将组件的属性挂载到shadowRoot中。

在getContent方法中,我们使用querySelector方法获取id为card-template的模板,并使用cloneNode方法创建一个模板副本。由于模板是HTML5的新特性,因此我们需要为HTML文件添加声明来确保浏览器正确解析模板。

在setContent方法中,我们使用getAttribute方法获取组件的属性,并将其挂载到shadowRoot中。我们还为关注按钮添加了一个点击事件,并在事件处理程序中触发了一个自定义事件。

最后,在JavaScript代码中,我们使用addEventListener方法监听组件的follow-event事件,并在事件处理程序中调用handleFollowEvent方法来处理按钮点击事件。当用户点击关注按钮时,handleFollowEvent方法将切换hasFollow属性,并重新渲染组件。
效果图如下
在这里插入图片描述
在这里插入图片描述

这是一个简单的Web Component示例,它介绍了如何使用Custom Elements、Shadow DOM和HTML Templates API来构建可重用的UI组件。通过使用这些API,我们可以将组件内部的样式和结构封装起来,防止外部样式干扰组件,并使开发者能够轻松地重复使用和维护组件。

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

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

相关文章

[Verilog] 加法器(半加法器 | 全加法器 | 串行加法器 | 并行加法器 | 十进制加法器)详解

前言 在数字电路中,加法器是一种常见的逻辑电路,用于将两个数字相加。本文将介绍如何使用Verilog实现各种加法器。 1 加法器种类 整数加法器 半加器(Half Adder):它是最简单的加法器,只能进行两个输入位的相加操作,不包括进位位。全加器(Full Adder):它是最基本的加…

第6课 用window API捕获麦克风数据并加入队列备用

今天是2024年1月1日&#xff0c;新年的第一缕阳光已经普照大地&#xff0c;祝愿看到这篇文章的所有程序员或程序爱好者都能在新的一年里持之以恒&#xff0c;事业有成。 今天也是我加入CSDN的第4100天&#xff0c;但回过头看一看&#xff0c;这么长的时间也没有在CSDN写下几篇…

SpringCloud-高级篇(九)

&#xff08;1&#xff09;Seata高可用 我们学习了Seata的各种用法了&#xff0c;Seata的服务是单节点部署的&#xff0c;这个服务如果挂了&#xff0c;整个事务都没有办法完了&#xff0c;下面我们学习Seata的高可用的知识。 实现高可用&#xff0c;还是比较简单&#xff0c;…

UntiyShader(六)Unity提供的Cg/HLSL语义

目录 前言 一、什么是语义(Semantics) 系统数值语义(system-value semantics) 二、Unity

QT上位机开发(抽奖软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 用抽奖软件抽奖&#xff0c;是一种很常见的抽奖方式。特别是写这篇文章的时候&#xff0c;正好处于2023年12月31日&#xff0c;也是一年中最后一天…

【华为机试】2023年真题B卷(python)-喊七的次数重排

一、题目 题目描述&#xff1a; 喊7是一个传统的聚会游戏&#xff0c;N个人围成一圈&#xff0c;按顺时针从1到N编号。 编号为1的人从1开始喊数&#xff0c;下一个人喊的数字为上一个人的数字加1&#xff0c;但是当将要喊出来的数字是7的倍数或者数字本身含有7的话&#xff0c;…

ceph之rados设计原理与实现:crush算法

执行命令 ceph osd crush dump可以查看当前集群crush信息 其中会输出可调crush参数"tunables"、规定的若干规则"rules"、以及crush map。 这些规则"rules"可以与存储池绑定&#xff0c;针对特定存储池执行自制的crush算法映射。 "crushmap…

新手快速上手掌握基础排序<二>快速排序快速入门

目录 引言 一&#xff1a;快速排序qsort的简介 1.qsort是一个库函数 2.库函数的查询了解方法 3.qsort的具体使用方法 4.qsort函数使用的一些注意点 5.qsort函数的特点 6.代码实现 (1)整数数组的快速排序 &#xff08;2&#xff09;结构体的快速排序&#xff08;学…

NumPy 中级教程——线性代数操作

Python NumPy 中级教程&#xff1a;线性代数操作 NumPy 提供了丰富的线性代数操作功能&#xff0c;包括矩阵乘法、行列式计算、特征值和特征向量等。这些功能使得 NumPy 成为科学计算和数据分析领域的重要工具。在本篇博客中&#xff0c;我们将深入介绍 NumPy 中的线性代数操作…

使用.Net nanoFramework 驱动ESP32的OLED显示屏

本文介绍如何使用.Net nanoFramework 驱动ESP32的OLED显示屏。我们将会从最基础的部分开始&#xff0c;逐步深入&#xff0c;让你能够理解并实现整个过程。无论你是初学者还是有一定经验的开发者&#xff0c;这篇文章都会对你有所帮助。 1. 硬件准备 1.1 ESP32开发板 这里我们…

samba的基础运用和配置

#主页传送门&#xff1a;江南的江 #每日鸡汤&#xff1a;落魄不是你吃不上饭&#xff0c;不是没人理你。只是你一方面在意别人的目光&#xff0c;另一方面却不清楚自己的方向在哪里。 #music 推荐&#xff1a;没有理想的人不伤心(新裤子) #初心和目标&#xff1a;在网络安全搞出…

解除mobaxterm会话14个限制

参考&#xff1a; https://www.jianshu.com/p/a40cbf068934 下载代码&#xff1a; git clone https://github.com/redrose2100/MobaXterm-keygen.git 查看当前系统用户名 查看mobaxterm版本号 执行&#xff1a; python MobaXterm-Keygen.py Administrator 20.2将生成的 Cust…

PyTorch的Tensor(张量)

一、Tensor概念 什么是张量&#xff1f; 张量是一个多维数组&#xff0c;它是标量、向量、矩阵的高维拓展 Tensor与Variable Variable是torch.autograd中的数据类型&#xff0c;主要用于封装Tensor&#xff0c;进行自动求导。 data: 被包装的Tensorgrad: data的梯度&…

基于OpenCv的车道检测

项目背景和步骤 车道检测是自动驾驶领域不可或缺的一环 具体步骤如下&#xff1a; 一、将图像灰度化&#xff0c;并进行适度的高斯滤波&#xff0c;剔除干扰 二、利用Canny边缘检测&#xff0c;检测出车道和其它物体的边缘 三、使用ROI区域截取&#xff0c;截取需要的部分&a…

Debian安装k8s记录

Debian安装k8s记录 在master和node上安装kube安装master安装node遇到的问题汇总1、kubelet.service报错 failed to pull image "registry.k8s.io/pause:3.6"2、node重启后报错&#xff0c;failed: open /run/flannel/subnet.env: no such file or directory 在master…

AI与数字化映像:颜值开端,功能至上_光点科技

在人工智能的浪潮中&#xff0c;AI数字人的兴起正成为一个不可忽视的现象。随着ChatGPT等生成式AI算法的进步&#xff0c;AIGC&#xff08;人工智能生成内容&#xff09;的应用呈现出爆发性增长&#xff0c;不仅在技术圈引起广泛关注&#xff0c;也为元宇宙及其相关产业链带来了…

[实践总结] 通过累加求和来学习 分支/合并框架

分支/合并框架 分支/合并框架的目的是以 递归方式将可以并行的任务拆分成更小的任务&#xff0c;然后将每个子任务的结果合并起来生成整体结果。 它是ExecutorService接口的一个实现&#xff0c;它把子任务分配给线程池&#xff08;称为ForkJoinPool&#xff09;中的工作线程。…

关于 android 热更新技术

Android应用实现热更新&#xff08;也称为动态更新或增量更新&#xff09;是指在不通过Google Play或其他应用市场重新发布完整APK包的情况下&#xff0c;应用能够从远程服务器下载并安装部分代码或资源文件以修复bug或增加新功能。这一机制提高了用户体验和产品迭代速度。以下…

循环业务异常外部处理导致的问题

问题描述&#xff1a; 在业务执行循环中&#xff0c;异常捕捉处理在循环外。当循环中的某个业务执行异常时&#xff0c;会影响后续业务的执行&#xff0c;因为没有采取相应措施来处理该异常并继续循环执行。 以下是示例代码&#xff0c;演示了在循环中执行多个业务操作并在异…

头歌:旅游网站大数据分析 - 数据抓取

package step1; import java.io.File; import java.io.IOException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document;public class Task {/*** param filePath 文件路径&#xff1a;backups/www.ctrip.com.txt/* return* throws IOException*/public Document getHt…