4 html5 web components原生组件详细教程

news2024/11/13 9:02:58

web components 前面我们已经介绍过,这一期我们就来讲一讲具体用法和这其中的关键只是点:

1 基本使用

如果我们想实现一个封装的原生组件,那就离不开使用js去封装,这里主要就是基于HTMLElement这个类,去创建创建一个子类,然后使用customElements.define去页面中注册这个组件。

export class dialog extends HTMLElement {
  constructor() {
    super(); // 必须首先调用 super()
    // 正确的做法
    if (!this.shadowRoot) {
      this.attachShadow({ mode: "open" }); // 或者 'closed' 根据需求
    }
    // 创建并添加样式到影子DOM中
    const style = document.createElement("style");
    style.textContent = `
        dialog {
          padding: 0;
          width: 300px;
          height: 200px;
          border: 1px solid #888;
        }

        dialog::backdrop {
          background: rgba(0,0,0,0.5);
        }
        dialog .title {
          box-sizing: border-box;
          padding: 0 5px;
          width: 100%;
          height: 30px;
          line-height: 30px;
          color: #fff;
          background: var(--primary-color);
        }
        dialog .close {
          float: right;
          cursor: pointer;
        }
        dialog .footer{
          margin-top: 40px;
        }
        `;
    this.shadowRoot.appendChild(style);
    // 创建并添加元素到影子DOM中
    const div = document.createElement("div");
    const mode = this.getAttribute("mode") || "show";
    const content = this.getAttribute("content") || "我是默认内容";
    div.classList.add("custom-dialog");

    const form = `<form method="dialog">
            ${content}
            <div class="footer">
            <button type="submit" value="submit">提交</button>
            <button type="submit" value="cancel">取消</button>
            </div>
            </form>`;
    const dialogContent = `
          <dialog class="dialog">
            <div class="title">dialog弹窗 <span class="close">X</span></div>
            <div class="content">
            ${["show", "modal"].includes(mode) ? content : form}
            </div>
          </dialog>
          <button class="show-dialog">${mode}弹窗</button>`;
    div.innerHTML = dialogContent;
    this.shadowRoot.appendChild(div);
    this.dialog = this.shadowRoot.querySelector(".dialog");

    const closeEvent = (detail) =>
      new CustomEvent("onclose", {
        detail,
        bubbles: true, // 允许事件冒泡
        composed: true, // 允许事件穿透shadow DOM
      });

    this.shadowRoot
      .querySelector(".show-dialog")
      .addEventListener("click", () => {
        if (mode === "show") {
          this.dialog.show();
        } else {
          this.dialog.showModal();
        }
      });
    this.shadowRoot.querySelector(".close").addEventListener("click", () => {
      this.dialog.close("top");
    });
    this.dialog.addEventListener("close", (e) => {
      // 触发自定义事件
      this.dispatchEvent(closeEvent(this.dialog.returnValue));
    });
  }
}

以上这个代码,我就封装了一个基于html5新标签dialog封装的弹窗组件,一下演示使用方法。

                <custom-dialog></custom-dialog>
                <custom-dialog
                  mode="modal"
                  content="modal模式演示有close监听"
                ></custom-dialog>
                <custom-dialog
                  mode="modal-form"
                  content="modal模式演示带有表单"
                ></custom-dialog>

以上代码我来简单分解下:

1 定义style

首先就是要给shadow Dom中要插入style标签和你自定义内容的html代码,这样来实现样式和html代码封装,主要的还是要实现代码的隔离。当然你接下来的交互,自然也要约束在你组件内部。

2 组件内查找节点

当然你js中节点事件处理,还是要基于this.shadowRoot.querySelector去做节点查找,然后使用原生的方法去做事件监听。

3 自定义事件派发:

 new CustomEvent("onclose", {
        detail,
        bubbles: true, // 允许事件冒泡
        composed: true, // 允许事件穿透shadow DOM
      });

这里就是定义一个自定义事件,然后使用this.dispatchEvent(closeEvent(this.dialog.returnValue))派发出去。

4 注册组件

接下来我们聊聊这个注册组件,以上代码仅仅是你定义组件,页面上还并不能直接使用。customElements.define(`custom-${i}`, dialog); 使用以上方法,才能在页面上以自己定义的名称使用。

2 插槽使用

插槽的使用给我们页面开发带来很大的方便,这里我们演示一下插槽的使用方法。在web components中插槽沿革执行了,组件的shadow-dom的特性,即插槽部分的样式定义和js是不受shadow-dom的this.shadowRoot的影响的,因为插槽为自定义内容,其内容被渲染也不属于组件shadow-dom内部,所以插槽被渲染出来dom结构并不在组件内部。

1 通过slot来定义插槽

<div slot="desc">
                  纯html+css实现,
                  无法实现更为复杂的功能和交互,而且无法实现shadow-root实现样式隔离
                </div>

2 使用插槽

在组件内部通过 <slot name="">来使用,如下。

const editorHtml = `
        <div class="editor-desc">
          <slot name="desc"></slot>
        </div>
        <div class="editor-code">
          <div class="code-type">${codeType}</div>
          <div class="code-container">
            <div class="code-lines"></div>
            <div class="code-content">
              <slot name="code"></slot>
            </div>
          </div>
        </div>
      `;

3 插槽的渲染

其渲染出来的效果如图:

f998e35753624121b1ae9f800be7b0dd.png

这里需要特别注意插槽为自定义内容,其内容被渲染也不属于组件shadow-dom内部,所以插槽被渲染出来dom结构并不在组件内部,特别实在做样式控制时要特别注意,需要在使用组件的页面上定义样式。如果是在嵌套环境更要注意。

3 样式部分

因为shadow-dom的特性,我们样式只可以写在组件内部。但是也有一些技巧。这里我分享一个就是做样式分离的方法。

const style = document.createElement("link");
    style.setAttribute("rel", "stylesheet");
    style.setAttribute("href", "./src/assets/editor.css");
    this.shadowRoot.appendChild(style);

 1 分离css方法

创建一个link标签,将样式从外部链接进来,这样就可以不用做style这么麻烦了。

当然后面我再讲一讲如何做html代码分离。

样式分离了,但是这里面又有一个问题就是,样式穿透问题。这里就不得不说几个基于web component的味蕾和和选择器。

:host 这个使用在组件样式内部,表示跟组件。使用这个我们可以约束根组件的样式。通常我们封装的组件都要通过一个div元素放在根组件内部,而这个div通常我们并没有给其设置类名。这时使用这个伪类就比较好。

:host() 只选择自身包含特定选择器的自定义元素;

:host-context() 选择拥有特定选择器父元素的自定义元素。

这些选择器后面详细来讲,这里我主要谈一下,样式的从父级项向下穿透的样式规则和需求。比如我们通常定义样式有全局级别的,页面级别的,还有小组件级别的。但是现在这种shadow-dom样式的完全隔离,向实现其实比较困难。

2 样式控制

我先说第一种:页面级别,其页面级别样式可以直接影响到自己页面本身和插槽的样式,这个也很好理解。因为插槽本身就是就是小组件外的内容,样式的作用域能控制到当前页面,也就能控制当前页面内的插槽。特别是在组件嵌套的情况下,当家控制要是要特别注意。类似于这个:host/:host()都可以往出派生,都比较容易控制。

第二种情况就比较特殊了,就是全局样式。全局样式如果想穿透组件,控制组件内部,其实是比较麻烦的。这里我来详细讲一下。主要使用了::part伪元素。

.page::part(case-container) {
  margin: 10px 0;
  border: 1px solid #f6f6f6;
}
.page::part(case-title) {
  padding: 0 10px;
  line-height: 25px;
  font-size: 16px;
}

.page::part(case-content) {
  background-color: #f6f6f6;
  padding: 10px;
}

3 样式穿透

这里大家看到,这个::part()括号中的是对应的组件.page中part属性的属性值的元素。

c68d15f1e78541c8a0d7001279f2bed6.png

如上图,这些html标签都被协商了part的key-value键值对。

前面的.page大家注意,这个地方本来是要写组件名称的,但如果写组件名称,作用域就太小了,所以我们给由相同需求的组件写一个类名,这样作用范围就更广,来实现更多需求全局样式穿透。

这个地方是给跟组件设置class的方法,建议大家在这个地方处理,这样的化,组件本身就具备了类名。但是::part不能派生,这也是个限制,希望官方后期能更新这个限制。

 this.setAttribute("class", "page");

1121b8f8cce64cb8aeaf8e9984367888.png

今天,就先分享到这,我的第一部分的原生html-web components项目部分已经马上完成,即将和大家见面。大家请关注。 

 

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

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

相关文章

【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

【HarmonyOS】深入理解Observed装饰器和ObjectLink装饰器&#xff1a;嵌套类对象属性变化 前言 之前就Observed和ObjectLink写过一篇讲解博客【HarmonyOS】 多层嵌套对象通过ObjectLink和Observed实现渲染更新处理&#xff01; 其中就Observe监听类的使用&#xff0c;Object…

prometheus监控linux虚拟机

前提条件已安装好prometheus和grafana&#xff0c;如果未安装请移步到docker部署prometheus 安装部署Prometheus,docker安装grafana安装部署Grafana。 1.二进制部署node-exporter采集器 2.1 采集器node-exporter下载 链接&#xff1a;https://pan.baidu.com/s/1hDmckSSl5X36…

【算法】BFS系列之 拓扑排序

【ps】本篇有 3 道 leetcode OJ。 目录 一、算法简介 二、相关例题 1&#xff09;课程表 .1- 题目解析 .2- 代码编写 2&#xff09;课程表 II .1- 题目解析 .2- 代码编写 3&#xff09;火星词典 .1- 题目解析 .2- 代码编写 一、算法简介 【补】图的基本概念 &#…

本地提权【笔记总结】

文章目录 服务命令at命令提权介绍适用版本复现 sc命令提权介绍适用版本复现 ps应用程序提权复现 进程注入进程迁移注入介绍条件复现 MSF自动化注入介绍getsystem原理 复现 MSF令牌窃取介绍复现 烂土豆提权介绍适用版本复现 UAC绕过介绍复现使用ask模块绕过使用bypassuac_sluihi…

谷歌的AI反击战:创始人谢尔盖·布林的回归与大模型组合的未来

近年来&#xff0c;随着AI技术的迅猛发展&#xff0c;尤其是ChatGPT等大语言模型的出现&#xff0c;全球科技格局正发生剧烈变化。作为曾经引领AI潮流的谷歌&#xff0c;在这场竞争中逐渐失去了领头羊的地位。然而&#xff0c;谷歌的创始人之一谢尔盖布林&#xff08;Sergey Br…

计算组合数

1.递推 #include<bits/stdc.h> #include<unordered_map> #include<unordered_set> using namespace std; #define int long long //可能会超时 #define PII pair<int,int> const int INF 0x3f3f3f3f, mod 1e9 7; const int N 2005; int a, b,n; …

手机自动化测试环境之夜神模拟器inspector部署验证

1、自动化测试环境部署_总览图检查表流程图 Python需要安装Appium-Python-Clicent去定位元素&#xff1b;Appium是一个中间的服务器&#xff0c;它需要依赖node.js&#xff0c;python的脚本通过appium和手机进行交互&#xff1b;手机app的环境都是java环境&#xff0c;先安装jd…

9、等保测评介绍

数据来源&#xff1a;9.等保测评介绍_哔哩哔哩_bilibili 信息系统等级测评 信息系统等级测评是测评机构依据国家信息安全等级保护制度的规定&#xff0c;按照相关管理规范和技术标准&#xff0c;对未涉及国家秘密的信息系统的安全等级保护状况进行检测评估的活动。 等级测评…

gitlab 的CI/CD (一)

前言 GitLab CI/CD 是一个内置在GitLab中的工具&#xff0c;用于通过持续方法进行软件开发&#xff1a; Continuous Integration (CI) 持续集成Continuous Delivery (CD) 持续交付Continuous Deployment (CD) 持续部署 持续集成的工作原理是将小的代码块推送到Git仓库…

JavaEE: 深入探索TCP网络编程的奇妙世界(三)

文章目录 TCP核心机制TCP核心机制三: 连接管理建立连接(三次握手)断开连接(四次挥手)三次握手/四次挥手 流程简图 TCP核心机制 书接上文~ TCP核心机制三: 连接管理 建立连接(三次握手),断开连接(四次挥手). 这里的次数指的是网络通信的次数,挥手/握手是形象的比喻(handshake…

PM2.5粉尘传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 3.工作原理介绍 4.粉尘浓度转化关系 5.空气污染指数 三、程序设计 main.c文件 PM25.h文件 PM25.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 GP2Y1014AU是日本夏普公司开发的一款光学灰尘浓度检测传…

探索 Web Speech API:实现浏览器语音识别与合成

引言 Web Speech API 是一项由 W3C 开发的 Web 标准&#xff0c;为开发者提供了在 Web 应用程序中实现语音识别和语音合成的能力。通过 Web Speech API&#xff0c;我们可以让网页与用户进行语音交互&#xff0c;实现更加智能化和便捷的用户体验。本文将深入探讨 Web Speech A…

14 vue3之内置组件trastion全系列

前置知识 Vue 提供了 transition 的封装组件&#xff0c;在下列情形中&#xff0c;可以给任何元素和组件添加进入/离开过渡: 条件渲染 (使用 v-if)条件展示 (使用 v-show)动态组件组件根节点 自定义 transition 过度效果&#xff0c;你需要对transition组件的name属性自定义。…

【Linux】当前进展

驱动层日志添加了下文件目录&#xff0c;函数&#xff0c;代码行的打印&#xff08;这里要小心&#xff0c;驱动目录源代码打印日志里边添进程号可能有问题&#xff0c;因为在驱动初始化的时候&#xff0c;内核还没有创建进程&#xff0c;不过猜测可以先不打印进程相关信息&…

python使用vscode 所需插件

1、导读 环境&#xff1a;Windows 11、python 3.12.3、Django 4.2.11、 APScheduler 3.10.4 背景&#xff1a;换系统需要重新安装&#xff0c;避免后期忘记&#xff0c;此处记录一下啊 事件&#xff1a;20240921 说明&#xff1a;记录&#xff0c;方便后期自己查找 2、插件…

Ansys Zemax | 如何使用琼斯矩阵表面

附件下载 联系工作人员获取附件 概览 琼斯矩阵 (Jones Matrix) 表面是一种非常简便的定义偏振元件的方法。这篇文章通过几个示例介绍了如何使用琼斯矩阵。 介绍 光线追迹程序一般只考虑光线的几何属性&#xff08;位置、方向和相位&#xff09;。光线传播到一个表面时的全…

SQL - 进阶语法(二)约束

1. SQL约束 约束用于约束表中的数据规则&#xff0c;如若存在违反行为&#xff0c;行为会被约束终止。 • NOT NULL 确保列不能有NULL值 如果添加一行新的数据&#xff0c;不能有null值&#xff0c;否则无法添加 新建表格 CREATE TABLE new_table( ID int NOT NULL, NAME …

梯形区域分解实现避障路径规划全覆盖路径规划

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言&#xff08;1&#xff09;功能&#xff08;2&#xff09;算法&#xff08;3&#xff09;参考链接&#xff08;4&#xff09;…

【服务器第二期】mobaxterm软件下载及连接

【服务器第二期】mobaxterm软件下载及连接 前言什么是SSH什么是FTP/SFTP mobaxterm软件介绍mobaxterm软件下载SSH登录使用方法1-新建ssh连接方法2-打开已有的ssh连接方法3-通过ssh命令建立连接 SFTP数据传输方法1-建立ssh连接后直接拖拽方法2-建立sftp连接再拖拽方法3-直接使用…

Nacos配置管理(2)-----配置热更新

有很多的业务相关参数&#xff0c;将来可能会根据实际情况临时调整。例如购物车业务&#xff0c;购物车数量有一个上限&#xff0c;默认是10&#xff0c;对应代码如下&#xff1a; 现在这里购物车是写死的固定值&#xff0c;我们应该将其配置在配置文件中&#xff0c;方便后期…