概念和使用

作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的HTML(以及相关的样式和脚本),有时您不得不写代码来呈现自定义UI控件,并且如果您不小心的话,多次使用它们会使您的页面变得一团糟。

Web Components旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。

Custom elements(自定义元素):一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。

Shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。

HTML templates(HTML模板):<template><slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

实现web component的基本方法通常如下所示:

  1. 创建一个类或函数来指定web组件的功能,如果使用类,请使用 ECMAScript 2015 的类语法(参阅类获取更多信息)。
  2. 使用 CustomElementRegistry.define() 方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。
  3. 如果需要的话,使用Element.attachShadow() 方法将一个shadow DOM附加到自定义元素上。使用通常的DOM方法向shadow DOM中添加子元素、事件监听器等等。
  4. 如果需要的话,使用 <template><slot> 定义一个HTML模板。再次使用常规DOM方法克隆模板并将其附加到您的shadow DOM中。
  5. 在页面任何您喜欢的位置使用自定义元素,就像使用常规HTML元素那样。

基础知识

生命周期

定义在自定义元素的类定义中的特殊回调函数,影响其行为:

connectedCallback: 当自定义元素第一次被连接到文档DOM时被调用。

disconnectedCallback: 当自定义元素与文档DOM断开连接时被调用。

adoptedCallback: 当自定义元素被移动到新文档时被调用。

attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。

选择器

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

示例

了解基础知识后,下面我们将实现一个基础的下拉选择组件(包含select和option)

要实现的功能

  1. 增加change事件
  2. 显示/隐藏下拉框
  3. 点击option时给input赋值
  4. 点击其它区域隐藏下拉框

具体实现

基础样式

class Select extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
// 元素的功能代码写在这里
const template = document.createElement("template");
template.innerHTML = `
<style>
:host {
position: relative;
display: inline-block;
}
.select-inner {
height: 34px;
border: 1px solid #cdcdcd;
box-sizing: border-box;
font-size: 13px;
outline: none;
padding: 0 10px;
border-radius: 4px;
}
.drop {
position: absolute;
top: 36px;
left: 0;
width: 100%;
padding: 4px 0;
border-radius: 2px;
overflow: auto;
max-height: 256px;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
display: none;
}
</style>
<input class="select-inner" readonly>
<div class="drop">
<slot></slot>
</div>
`;
const shadowELe = this.attachShadow({ mode: "open" });
const content = template.content.cloneNode(true);
shadowELe.appendChild(content);
}
}
class Option extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
// 元素的功能代码写在这里
const template = document.createElement("template");
template.innerHTML = `
<style>
:host {
position: relative;
}
.option {
height: 32px;
line-height: 32px;
box-sizing: border-box;
font-size: 13px;
color: #333333;
padding: 0 10px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.option:hover {
background-color: #f4f4f4;
}
</style>
<div class="option">
<slot></slot>
</div>
`;
const shadowELe = this.attachShadow({ mode: "open" });
const content = template.content.cloneNode(true);
shadowELe.appendChild(content);
}
static get observedAttributes() {
return ["value"];
}
}
customElements.define("ivy-select", Select);
customElements.define("ivy-option", Option);

增加事件

class Select extends HTMLElement {
constructor() {
// 必须首先调用 super 方法
super();
// 元素的功能代码写在这里
...
this.$input = shadowELe.querySelector(".select-inner");
this.dropEle = shadowELe.querySelector(".drop");
this.value === null;
this.$input.addEventListener("click", () => {
this.dropEle.style.display = "block";
});
this.dropEle.addEventListener("click", (ev) => {
const target = ev.target;
const nodeName = target.nodeName.toLowerCase();
if (nodeName === "ivy-option") {
this.value = target.getAttribute("value");
this.$input.setAttribute("value", target.innerHTML);
// 自定义事件
this.dispatchEvent(
new CustomEvent("change", {
detail: {
value: this.value,
},
})
);
this.dropEle.style.display = "none";
}
});
this.BodyClick = () => {
this.dropEle.style.display = "none";
};
}
connectedCallback() {
document.addEventListener("click", this.BodyClick, true);
}
disconnectedCallback() {
document.removeEventListener("click", this.BodyClick);
}
}

需要注意的是,如果需要在元素属性变化后,触发 attributeChangedCallback()回调函数,你必须监听这个属性。这可以通过定义observedAttributes() get函数来实现,observedAttributes()函数体内包含一个 return语句,返回一个数组,包含了需要监听的属性名称:

static get observedAttributes() {return ['value']; }

完整代码:传送门

web component基础概念及使用的更多相关文章

  1. 移动端web开发基础概念

    最近在了解移动端web开发的相关知识,有些概念总是模糊不清,这次花费了一些时间整体的梳理了一遍. 分辨率 分辨率可以从显示分辨率与图像分辨率两个方向来分类.显示分辨率(屏幕分辨率)是屏幕图像的精密度, ...

  2. 编程语言十万个为什么之java web的基础概念

    1.什么是JAVA Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由SunMicrosystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaSE, Ja ...

  3. web万维网 -- 基础概念

    Web(万维网World Wide Web的简称)是个包罗万象的万花筒,不同的人从不同的角度观察,对于Web究竟是什么会得出大不相同的观点. 百科:web(World Wide Web)即全球广域网, ...

  4. 【面试】【Linux】【Web】基础概念

    1. HTTP https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol 2. TCP handshake https://en.wikipe ...

  5. Web Component 文章

    周末无意中了解了Web Component的概念. http://blog.amowu.com/2013/06/web-components.html http://www.v2ex.com/t/69 ...

  6. Web Service基础——基础概念

    1. Web Service基本概念 Web Service(Web服务)是一种远程调用技术,他的作用就是从远程系统中获取业务数据.具体来说,Web Service可以让你的网站使用其他网站的资源,比 ...

  7. (数据科学学习手札102)Python+Dash快速web应用开发——基础概念篇

    本文示例代码与数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的新系列教程Python+Dash快 ...

  8. JavaBean 基础概念、使用实例及代码分析

    JavaBean 基础概念.使用实例及代码分析 JavaBean的概念 JavaBean是一种可重复使用的.且跨平台的软件组件. JavaBean可分为两种:一种是有用户界面的(有UI的):另一种是没 ...

  9. 【UML】NO.70.EBook.9.UML.4.001-【PowerDesigner 16 从入门到精通】- 基础概念

    1.0.0 Summary Tittle:[UML]NO.70.EBook.9.UML.4.001-[PowerDesigner 16 从入门到精通]-  基础概念 Style:DesignPatte ...

  10. 快速入门系列--WCF--01基础概念

    转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式.记得从自己最开始做MFC时,就使用过Named Pipe命名管道,之后做Winfo ...

随机推荐

  1. 一文了解网络编程之走进TCP三次握手和HTTP那些你不知道的事

    受到很多引人入胜的标题党的影响,我终于决定,要起一个比他们还标题党的题目,打不过还不能加入吗,嘿嘿. 网络编程一直是我的弱项,其实归根结底还是我太懒了,一看到那个osi七层模型,TCP/IP模型还有那 ...

  2. 千字干货分享:一文教你ABI增强分析,BI的未来就在这里!

    自2017年以来,智能概念开始出现,各类商业智能BI应用的使用门槛逐渐降低,商业智能BI制造商主要竞争增强分析的能力.<2020年Gartner分析与BI平台魔法象限报告>指出,2020年 ...

  3. 重新点亮shell————awk 控制语句[十三]

    前言 简单介绍一下控制语句. 正文 例子1: 例子2: 例子3 for循环: 例子4, sum会复用: 同样,其他的while 和 do while 也是可以在awk中使用的. 结 下一节awk数组.

  4. 重新整理.net core 计1400篇[四] (.net core 修改sdk )

    前言 可能有些人还不知道什么是sdk,software development kit,中文是软件开发包的意思. 然后什么是软件开发包? 软件开发工具包是一些被软件工程师用于为特定的软件包.软件框架. ...

  5. ImageJ软件使用教程(三):目标计数

    目录 多点工具法 阀值分割法 二值化 填充分割 自动计数 显示结果 总结 参考资料 本文以钢筋计数为例,讲解一下如何使用ImageJ软件进行计数,这里只介绍两种方法: 多点工具法 阀值分割法 钢筋计数 ...

  6. 容器启动流程(containerd 和 runc)

    启动流程 containerd 作为一个 api 服务,提供了一系列的接口供外部调用,比如创建容器.删除容器.创建镜像.删除镜像等等.使用 docker 和 ctr 等工具,都是通过调用 contai ...

  7. dva使用yarn编译出错

    1. 报错信息 ./src/models/example.jsModule build failed: TypeError: /Users/user/Desktop/learn-code/10.Rea ...

  8. DataWorks 如何撑起阿里99%的数据开发?

    阿里妹导读: DataWorks是阿里巴巴自主研发,支撑阿里巴巴经济体99%数据业务建设和治理,每天数万名数据开发和算法开发工程师在使用.从2010年起步到目前的版本,经历了多次技术变革和架构升级,也 ...

  9. MySQL 深潜 - MDL 锁的实现与获取机制

    简介:本文将介绍在 MDL 系统中常用的数据结构及含义,然后从实现角度讨论 MDL 的获取机制与死锁检测,最后分享在实践中如何监控 MDL 状态. ​ 作者 | 泊歌 来源 | 阿里技术公众号 一 背 ...

  10. 阿里 & 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源

    ​简介:经历近 3 年时间,在阿里集团及蚂蚁集团共建小组的努力下,OpenSumi 作为国内首个强定制性.高性能,兼容 VS Code 插件体系的 IDE 研发框架,今天正式对外开源. ​ 作者 | ...