web component基础概念及使用

简介: web component基础概念及使用

概念和使用

作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的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']; }

完整代码:传送门


相关文章
|
7月前
|
SQL 分布式计算 Hadoop
Azkaban【基础 01】核心概念+特点+Web界面+架构+Job类型(一篇即可入门Azkaban工作流调度系统)
【2月更文挑战第6天】Azkaban【基础 01】核心概念+特点+Web界面+架构+Job类型(一篇即可入门Azkaban工作流调度系统)
527 0
|
Java 测试技术 Spring
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成(二)
Spring入门&控制反转(或依赖注入)&AOP的关键概念& 多配置文件&与web集成
|
6月前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
66 0
|
4月前
|
开发框架 JavaScript 前端开发
Web Component -- 即将爆发的原生的 UI 组件化标准
Web Component -- 即将爆发的原生的 UI 组件化标准
|
4月前
|
前端开发 JavaScript 数据可视化
Python+Dash快速web应用开发——基础概念篇
Python+Dash快速web应用开发——基础概念篇
|
4月前
|
存储 安全 搜索推荐
深入探讨Session和Cookie的概念、用途以及如何在Java Web开发中有效地使用它们进行用户状态管理。
在Java Web开发中,Session和Cookie是管理用户状态的核心技术。Session存储于服务器端,通过唯一的Session ID识别用户,确保数据安全与隐私;Cookie则存储于客户端,用于记录用户偏好等信息。两者各有优势:Session适合存储敏感数据,但需合理管理避免资源浪费;Cookie便于持久化存储,但在安全性上需谨慎设置。开发者可通过Servlet API轻松操作二者,实现个性化用户体验与应用性能优化。
68 2
|
4月前
|
Java Docker 微服务
微服务架构的概念、特点以及如何在Java Web开发中实现微服务。
微服务架构的概念、特点以及如何在Java Web开发中实现微服务。
101 1
|
7月前
|
JavaScript 前端开发 开发者
在Web开发中,事件处理是一个至关重要的概念
【5月更文挑战第17天】Vue.js的事件处理是其核心特性之一,允许开发者响应用户操作。通过v-on(或@)指令绑定DOM事件到方法,实现交互。事件修饰符如.stop、.prevent等简化处理逻辑。此外,Vue支持自定义事件,便于组件间通信,如子组件通过$emit触发事件,父组件使用v-on监听并响应。理解这些机制能帮助开发者更有效地管理Vue应用的事件流程。
51 0
|
前端开发 Java 数据库连接
学习Java Web开发的关键技术和概念
学习Java Web开发的关键技术和概念
|
7月前
|
弹性计算 前端开发 JavaScript
前端新趋势?有了Web Component,还用纠结Vue或React?
Web Component 的概念最早在 2011 年被 Google 提出,并在 2018 年 V1 版本开始被主流浏览器所支持(除了 IE)。