Web Components入门教程示例详解

目录
  • Web Components不兼容IE
    • 困境
    • Web Components核心技术
      • 自定义元素
      • HTML模板(template、slot)
      • shadow root(影子Dom)

Web Components不兼容IE

2011年提出Web Components,为了解决代码复用问题,早于React、Vue;

相对于React、Vue组件,Web Components是原生组件,不限制接入方的技术,可以接入到React、Vue等技术框架中

困境

  • 兼容性不足,需要主流浏览器的支持,需要平缓的过渡
  • 没有标准的数据绑定机制、在处理自定义元素内部数据、UI更新、组件间参数传递时不够便捷和友好,目前来看大多还依赖于操控dom去实现UI更新

Web Components核心技术

  • 自定义元素
  • HTML模板
  • 影子Dom

自定义元素

使用 window.customElements.define 自定义html标签元素,自定义元素需要我们用JS封装一个,我们在html内使用的自定义元素custom-button就是该类的实例;

自定义标签的生命周期 constructor -> attributeChangedCallback -> connectedCallback

 <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <custom-button></custom-button>
    <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          console.log("this", this);
          const info = document.createElement("span");
          info.setAttribute("class", "test_custom");
          info.textContent = "自测自定义标签";
          var container = document.createElement("div");
          container.classList.add("container");
          this.append(info, container);
        }
      }
      customElements.define("custom-button", CustomButton);
    </script>
  </body>
</html>

我们可以看到CustomButton继承了HTMLElement,也就是继承了HTML元素的特性,最后我们执行了this.append(DOM),也就是将元素内容添加到当前自定义标签内,this表示自定义元素实例

HTML模板(template、slot)

<template>:包含一个html片段,不会在html初始化时渲染。主要作用是:通过JavaScript获取该代码片段将其放入自定义标签内显示,主要作用于自定义标签

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <template id="test_template">
      <div class="container">
        <span class="test_custom">自测自定义标签</span>
      </div>
    </template>
    <custom-button></custom-button>
    <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          const dom = document.querySelector("#test_template").content;
          this.append(dom);
        }
      }
      customElements.define("custom-button", CustomButton);
    </script>
  </body>
</html>

我们可以发现这种写法相对于前一种方式,更加易读以及便捷

<slot>插槽:给模板元素传值,增强模板元素的灵活性和通用性。 slot在使用过程中具备以下特性

  • 必须在影子Dom种使用,否则不具备插槽的效果
  • 给 Slots 传值的元素必须是自定义元素的直接子元素,否则传值失效
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <template id="test_template">
      <div class="container">
        <span class="test_custom">自测自定义标签</span>
        <slot name="userName" slot="userName"></slot>
      </div>
    </template>
    <custom-button>
      <div class="name_cls" slot="userName">张三</div>
    </custom-button>
    <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          const dom = document.querySelector("#test_template").content;
          this.append(dom);
        }
      }
      customElements.define("custom-button", CustomButton);
    </script>
  </body>
</html>

通过上图发现我们插入的<div class="name_cls">张三</div>并没有插入到container节点内,主要是因为我们的slot没有用在影子dom种,所以浏览器将<div class="name_cls">张三</div>当成其正常的元素进行渲染了;

 <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          const shadow = this.attachShadow({ mode: "closed" });
          const dom = document.querySelector("#test_template").content;
          shadow.append(dom);
        }
      }
      customElements.define("custom-button", CustomButton);
</script>

当我们将slot插入在影子dom,可以发现slot生效了;

另外需要注意的一个点,当使用slot的时候下边这个用法是错误的

// 错误示范
 <custom-button>
     <div> //不能有这一层级
       <div class="name_cls" slot="userName">张三</div>
     </div>
</custom-button>

shadow root(影子Dom)

浏览器提供了一种机制用于隔离一段代码和另一段代码,说到这里你肯定想到iframe,但有时候iframe会显得非常的沉重以及隔离了太多,导致我们使用起来非常的麻烦; 我们可以利用shadow root将CSS和HTML绑定在一起封装成组件,并且其支持天然的样式隔离;

Element.attachShadow()  方法给指定的元素挂载一个 Shadow DOM,并且返回对 ShadowRoot 的引用。

 <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          const shadow = this.attachShadow({ mode: "closed" });
          const dom = document.querySelector("#test_template").content;
          shadow.append(dom);
        }
      }
      customElements.define("custom-button", CustomButton);
</script>

this.attachShadow({ mode: "closed" })closed表示表示 Shadow DOM 是封闭的,不允许外部访问。如果mode的值是open,则表示内部的节点可以被外部访问;

添加样式

  • 如果自定义元素需要样式,我们可以定义全局的样式,例如
custom-button{
  ...
}
  • 正常情况我们应该将样式和自定义标签封装在一起
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>222</div>
    <template id="test_template">
      <div class="container">
        <span class="test_custom">自测自定义标签</span>
        <slot name="userName"></slot>
      </div>
      <style>
         :host {
          position: relative;
          top: 10px;
        }
        .test_custom {
          color: red;
        }
        div {
          border: 1px solid black;
        }
      </style>
    </template>
    <custom-button>
      <span slot="userName">张三</span>
    </custom-button>
    <script>
      class CustomButton extends HTMLElement {
        constructor() {
          super();
          const shadow = this.attachShadow({ mode: "closed" });
          const dom = document.querySelector("#test_template").content;
          shadow.append(dom);
        }
      }
      customElements.define("custom-button", CustomButton);
    </script>
  </body>
</html>

:host:表示当前的自定义元素节点;

另外可以发现我们定义的div样式只作用于了影子dom内部元素,对于外部的div没有任何影响,证明了影子Dom的样式隔离特性

以上就是Web Components入门教程详解的详细内容,更多关于Web Components入门教程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Web Components实现类Element UI中的Card卡片

    目录 引言 Web Components 核心组成 1. Custom Elements 2. Shadow DOM 3. templates 和 slots 完整代码 Web Components vs Vue Components Web Components 生命周期回调函数 优点 and 缺点 七.基于web components的框架 引言 Web Components 是一个浏览器原生支持的组件化方案,允许你创建新的自定义.可封装.可重用的HTML 标记.不用加载任何外部模块,直接就

  • Vue3 构建 Web Components使用详解

    目录 引言 构建 Web Components 属性 事件 插槽 子组件样式问题 方法 总结 引言 有时候想写一个无关框架组件,又不想用原生或者 Jquery 那套去写,而且还要避免样式冲突,用 Web Components 去做刚觉就挺合适的.但是现在 Web Components 使用起来还是不够灵活,很多地方还是不太方便的,如果能和 MVVM 搭配使用就好了. 早在之前 Angular 就支持将组件构建成 Web Components,Vue3 3.2+ 开始终于支持将组建构建成 Web

  • webpack 5.68.0版本教程示例详解

    目录 起步 1. 基本安装 2. 配置出入口 plugin 1. html-webpack-plugin 2. progress-bar-webpack-plugin loader 1. css-loader与style-loader 2. url-loader与file-loader 3. sass-loader 4. postcss-loader 5. babel-loader 搭建环境 1. 开发环境与生产环境 2. 配置别名 代码分离 1. webpack-bundle-analyzer

  • vue实例成员 插值表达式 过滤器基础教程示例详解

    目录 一. 什么是Vue 二.为什么学Vue 三.如何使用Vue 下载安装? 插值表达式 四.vue特点 1.虚拟DOM 2.数据的双向绑定 3.单页面应用 4.数据驱动 五.Vue实例 六.实例成员 - 挂载点 | el - 自定义插值表达式括号| delimiters - 数据 | data - 过滤器 | filters - 方法 | methods - js对象(即字典)补充 - 插值表达式转义 | delimters - 计算属性 | computed - 监听属性 | watch 一

  • PHP与Web页面的交互示例详解二

    前言 在<PHP学习笔记-PHP与Web页面的交互1>笔记中讲解了form表单的一些属性,包括它的输入域标记.选择域标记和文字域标记的写法,接下来的内容就是讲如何获取表单数据以及PHP数据的传递,包括对各种控件值的获取. 插入表单 提交表单之前一定得有表单,当我们的表单创建完毕后可以将表单插入Web页中,代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://w

  • PHP与Web页面的交互示例详解一

    前言 这篇笔记记录的是Web表单的相关操作,Web表单主要用来在网页中发送数据到服务器.比如在日常开发中,提交注册时需要提交表单,表单从客户端传送到服务器,经过服务器处理后,再将用户所需要的信息传递回客户端,进而实现PHP与Web表单的交互. 表单 使用<form>元素,并在其中插入相关的表单元素,即可创建一个表单. 表单结构: <form name="form_name" method="method" action="url"

  • 基于gin的golang web开发:路由示例详解

    Gin是一个用Golang编写的HTTP网络框架.它的特点是类似于Martini的API,性能更好.在golang web开发领域是一个非常热门的web框架. 启动一个Gin web服务器 使用下面的命令安装Gin go get -u github.com/gin-gonic/gin 在代码里添加依赖 import "github.com/gin-gonic/gin" 快速启动一个Gin服务器的代码如下 package main import "github.com/gin-

  • MySql数据类型教程示例详解

    目录 1.简要概述 2. MySQL数据类型详解 1) 字符串类型 2) 整数类型 3)浮点数类型 4)日期/时间类型 1.简要概述 为什么要开通MySQL这个学习板块呢?因为这是一名数据分析师必要的一项技能.分析数据什么最重要?当然是数据,既然如此!在数据呈现爆发式增长的年代,怎么能够不学学数据库呢?其实这也是很多读者朋友希望看到的,也是他们建议我写的. 难者不会,会者不难!其实网上很多MySQL的总结文章,不可否认,知识点写的都很全,但是呢!这个只是会使用MySQL数据库的朋友的一个查询手册

  • node.js中Util模块作用教程示例详解

    目录 从类型判断说起 严格相等 Error First & Promise 调试与输出 从类型判断说起 在 JavaScript 中,进行变量的类型校验是一个非常令人头疼的事,如果只是简单的使用 typeof 会到各种各样的问题. 举几个简单的: console.log(typeof null) // 'object' console.log(typeof new Array) // 'object' console.log(typeof new String) // 'object' 后来,大

  • C语言指针教程示例详解

    目录 指针 内存 指针类型 指针运算 二级指针 指针数组 指针 指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作.另外,通过指针可以更便捷地操作数组.在一定意义上可以说,指针是 C 语言的精髓. 概念解释就不去搬原定义了,又臭又长不好理解,精炼两点就是: 1.指针是内存中的一个最小单元的编号,也就是地址: 2.平时我们说的指针,通常是指指针变量,用来存储内存地址的变量 也就是说:指针就是地址,口语中指针通常是指针变量 内存 要搞明白指针首先要搞

  • C语言数据结构顺序表中的增删改(头插头删)教程示例详解

    目录 头插操作 头删操作 小结 头插操作 继上一章内容(C语言数据结构顺序表中的增删改教程示例详解),继续讲讲顺序表的基础操作. 和尾插不一样,尾插出手阔绰直接的开空间,咱头插能开吗?好像没听说过哪个接口可以在数据前面开一片空间吧,那我们思路就只有一个了——挪数据.那应该从第一位开始挪吗?注意,这和 memcpy 函数机制是一样的,并不意味着后面数据一起挪动,也不会彼此独立,而是相互影响,挪动的数据会对后面数据进行覆盖. 那我们的逻辑就应该是从后往前挪,那我们就直接定一个下标,指向这段空间的最后

  • Go gRPC环境安装教程示例详解

    目录 前言 安装 protobuf 安装相关包 创建并编译proto文件 VSCode-proto3插件介绍 前言 gRPC 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计,带来诸如双向流.流控.头部压缩.单 TCP 连接上的多复用请求等特.这些特性使得其在移动设备上表现更好,更省电和节省空间占用. 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务. gRPC 默认使用 protocol

随机推荐