实用 Custom Elements:快速构建定制化 Web 组件

阅读时长 25 分钟读完

Custom Elements 是 Web Components API 的一部分,它可以让我们创建自定义的 HTML 元素,并在需要的时候在页面上使用。它不仅提供了一种更好的组织代码的方式,还可以提高代码的复用性和可维护性。在本文中,我们将深入 Custom Elements,介绍它的使用方法和示例,帮助你快速构建定制化的 Web 组件。

Custom Elements 的基础

Custom Elements 允许我们创建一个自定义的 HTML 元素,例如 <my-component>,并定义其外观和行为。在定义一个 Custom Element 之前,需要先定义一个类:

这个类继承自 HTMLElement,代表着将要创建的元素类型。接下来,我们需要调用 window.customElements.define 函数来注册这个 Custom Element:

这里的第一个参数 'my-component',是我们将要创建的元素的标签名称,可以是任意有效的 HTML 标签名称,但必须包含一个连字符。

至此,我们就创建了一个最简单的 Custom Element,此时我们可以在 HTML 中使用 <my-component> 标签来创建这个元素。但是,这个元素并没有什么实际的作用,因为我们还没有为它添加任何 UI 或逻辑。

Custom Elements 的生命周期

Custom Elements 拥有自己的生命周期,当 Custom Element 第一次创建时,将会依次调用以下生命周期函数:

1. constructor()

在 Custom Element 创建时调用,用来初始化元素。如果定义了多个构造函数,则将只调用最后一个构造函数。

2. connectedCallback()

在 Custom Element 加载至页面 DOM 时调用,用来添加 UI 和逻辑。这是添加 UI 和初始化数据的最佳时机,因为这时元素已被 DOM 解析,可以直接操作 HTML 和 CSS。

3. disconnectedCallback()

在 Custom Element 从页面 DOM 中移除时调用,用来释放资源和清除引用。例如,取消订阅事件和清除内存缓存等。

4. attributeChangedCallback(name, oldValue, newValue)

当 Custom Element 中指定的属性发生变化时调用,可以用于更新元素的 UI 和数据。此时可以通过 this.attributes 来获取所有的属性值。

Custom Elements 的属性

通过使用 class PropertiesobservedAttributes 来为 Custom Element 添加属性。

1. 使用 class Properties

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------ --- -------------------- -
    ------ -------- ----------
  -

  ------------- -
    --------
  -

  --- ------ -
    ------ --------------------------
  -

  --- ----------- -
    ------------------------- -------
  -

  --- -------- -
    ------ ----------------------------
  -

  --- ------------- -
    --------------------------- -------
  -
-

在上面的代码中,我们通过 observedAttributes 定义了需要观察的属性,在这里是 nameamount。在类中我们又定义了 getter 和 setter 函数,可以用来设置或获取相应的属性值。在 Custom Element 的 connectedCallback() 函数中,我们可以自由地使用这些属性:

2. 使用 observedAttributes

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------ --- -------------------- -
    ------ -------- ----------
  -

  ------------- -
    --------
  -

  ------------------------------ --------- --------- -
    ------ ------ -
      ---- -------
        ---------- - ---------
        ------
      ---- ---------
        ------------ - ---------
        ------
    -
  -

  --- ------ -
    ------ -----------
  -

  --- ----------- -
    ------------------------- -------
  -

  --- -------- -
    ------ -------------
  -

  --- ------------- -
    --------------------------- -------
  -
-

在这个例子中,我们也定义了 nameamount 两个属性,但是使用了另一种方式来为它们添加观察。在 attributeChangedCallback(name, oldValue, newValue) 函数中,我们可以通过 name 参数来判断属性名称,并将新值赋给相应的类变量。

Custom Elements 的样式

Custom Elements 可以包含自己的样式表,这些样式表可以是内嵌样式、外部样式表或 Shadow DOM 样式表。

1. 内嵌样式

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------------- -
    --------
    
    ----- ----- - --------------------------------
    ----------------- - -
      -- -
        ------ -----
      -
    --
    ------------------- ----- ------ -----------------
  -

  ------------------- -
    ------------------------- - ---------- ------------
  -
-

------------------------------------- -------------

在这个例子中,我们使用 attachShadow({ mode: 'open' }) 来为 Custom Element 创建 Shadow DOM,并通过 shadowRoot 引用来获取 Shadow DOM 的根节点。接着我们在 Shadow DOM 中添加了一个内嵌样式表,并在 connectedCallback() 中添加了 UI。

2. 外部样式表

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------------- -
    --------
    
    ----- ---- - -------------------------------
    ------------------------ --------------
    ------------------------- --------------------
    ------------------- ----- ------ ----------------
  -

  ------------------- -
    ------------------------- - ---------- ------------
  -
-

------------------------------------- -------------

在这个例子中,我们创建了一个外部样式表,并将其添加到了 Shadow DOM 中。在 HTML 中,我们可以通过以下方式来添加这个 Custom Element:

3. Shadow DOM 样式表

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------------- -
    --------
    
    ----- ----- - --------------------------------
    ----------------- - -
      ----- -
        -------- ------
        ------- --- ----- -----
        -------- ------
      -

      -- -
        ------ -----
      -
    --
    ------------------- ----- ------ -----------------
  -

  ------------------- -
    ------------------------- - ---------- ------------
  -
-

------------------------------------- -------------

在这个例子中,我们在 Shadow DOM 中添加了一个 Shadow DOM 样式表,通过 :host 选择器来选择 Custom Element 的根元素,并为其应用 CSS 样式。

Custom Elements 的事件

Custom Elements 可以接收和发出自定义事件,这些事件可以通过自定义的 dispatchEvent() 函数和自定义的 addEventListener() 函数来创建和监听。

1. dispatchEvent()

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------------- -
    --------
  -

  ------------------- -
    ----- ------ - ---------------------------------
    ------------------ - ------ -----
    -------------------------------- -- -- -
      ---------------------- ----------------------- -
        -------- -----
        --------- -----
        ------- - -------- ------ ------ -
      ----
    ---
    -------------------------
  -
-

------------------------------------- -------------

在这个例子中,当 <button> 被点击时,我们使用 dispatchEvent() 函数来触发一个自定义事件 my-event。这个函数接受一个 CustomEvent 对象作为参数,它可以在其 detail 属性中传递自定义的数据。在这个例子中,我们传递了一个 message: 'Hello World' 的对象。

2. addEventListener()

-- -------------------- ---- -------
----- ----------- ------- ----------- -
  ------------- -
    --------
  -

  ------------------- -
    ----- ------ - ---------------------------------
    ------------------ - ------ -----
    -------------------------------- -- -- -
      ---------------------- ----------------------- -
        -------- -----
        --------- -----
        ------- - -------- ------ ------ -
      ----
    ---
    -------------------------

    --------------------------------- - -- -
      ------------------------------
    ---
  -
-

------------------------------------- -------------

在这个例子中,我们在 Custom Element 中添加了一个 my-event 的事件监听器,通过 e.detail 来获取事件的详情数据。当 <button> 被点击时,我们触发了这个自定义事件,并在控制台中输出了 Hello World

Custom Elements 的示例

接下来,我们将以一个实例来演示 Custom Elements 的应用。

1. 创建一个 TodoList

我们将创建一个 TodoList 组件,这个组件可以添加、删除和完成任务。首先我们需要一个 HTML 模板:

-- -------------------- ---- -------
--------- ------------------------
  -------
    ----- -
      -------- ------
      ------- --- ----- -----
      -------- ------
    -

    -- -
      ----------- --
    -

    ----- -
      -------- ------
    -

    ----------------------- ------------------- ------ -
      ------- ------
      -------- ------
    -

    ------------------- ------ -
      ------ -----
    -

    ---------- -
      ---------------- -------------
    -
  --------
  -----------------
  ------
    -------
      ------ --------------- -------------- --
      ---- --- -- --------
    --------
    --------- ------------------------
      -------
        ------ --------------- ---------------- --
        ----- -----------------------
        ------ ----------- ------------ --
        ------- ------------------------------
      --------
    -----------
    --- ---------------
    ------ ----------- --------- ---------------- - --- ----- --
    ------- ------------ -------------
  -------
-----------

这个 HTML 展示了一个 TodoList 的样式,它包含了:

  • 一个 <h3> 标题;
  • 一个 Mark all as complete 复选框;
  • 一个 <ul> 列表,用来显示所有的任务;
  • 一个添加任务的输入框和按钮。

接下来,我们将通过 Custom Elements 来完成 TodoList 的逻辑部分。

2. 完成 TodoItem 的逻辑

首先我们先定义 TodoItem 这个组件:

-- -------------------- ---- -------
----- -------- ------- ----------- -
  ------------- -
    --------
    
    ----- -------- - ------------------------------------------------------
    ------------------- ----- ------ -----------------------------------------
    
    ------------- - -------------------------------------------
    ------------ - ------------------------------------------
    --------- - ---------------------------------------
    ----------- - -----------------------------------------
    
    ---------------------------------------- -- -- -
      ---------------------- --------------------- -
        -------- -----
        --------- -----
        ------- - -------- --------------------- -
      ----
    ---
    
    ----------------------------------------- -- -- -
      -------------------------- - -------
      ----------------------- - ---------------
      -------------------
    ---
    
    ---------------------------------- -- -- -
      ----------------------- - -------
      -------------------------- - ---
      ------------------------ - ----------------
    ---
    
    ------------------------------------- -- -- -
      ---------------------- --------------------- -
        -------- -----
        --------- ----
      ----
    ---
  -
  
  ------ --- -------------------- -
    ------ --------------
  -

  ------------------------------ --------- --------- -
    -- ----- --- ------------ -
      --------------------- - --------- --- --------
      -------------------
    -
  -

  --- ----------- -
    ------ -------------------------------
  -

  --- ---------------- -
    ------------------------------ -------
    -------------------
  -
  
  ------------- -
    -- ----------------------- -
      ----------------------------------------
    - ---- -
      -------------------------------------------
    -
  -
-

---------------------------------- ----------

在这个组件中,我们利用了一些事件来处理 TodoItem 的逻辑:

  • change 事件用来触发选中状态的变化;
  • dblclick 事件用来触发编辑状态的变化;
  • blur 事件用于处理编辑状态的取消操作;
  • click 事件用来触发任务的删除操作。

同时,我们也提供了一些属性:

  • completed 属性,用于表示任务的选中状态。

最后,我们需要为 TodoItem 的 CSS 样式添加额外的样式,以实现选中状态:

3. 完成 TodoList 的逻辑

接下来我们使用 TodoItem 来定义 TodoList:

-- -------------------- ---- -------
----- -------- ------- ----------- -
  ------------- -
    --------
    
    ----- -------- - ------------------------------------------------------
    ------------------- ----- ------ -----------------------------------------
    
    ------------- - --------------------------------------------
    -------------- - ---
    
    ---------------------------------------------------------------- - -- -
      -------------------
      ----- ---- - ----------------------------------------------------
      -- ------ -
        -------------------
        -------------------------------------------- - ---
        ----------------------
      -
    ---
    
    ---------------------------------------- -- -- -
      ----- ------- - ----------------------
      --------------------------- -- -
        -------------- - --------
      ---
    ---
  -
  
  ------------- -
    ----- ---- - ---------------------------- - --- ----------- ---
    ----- -- - ---------------------------------------
    --------- - -----
    -------------- - ------
    ------------------------ - -----
    ------------------------------- -- -- -
      ----------------------
    ---
    ------------------------------- -- -- -
      ----------------------
    ---
    --------------------------
    ---------------------
  -
  
  ---------------- -
    ----- ----- - -----------------------------
    --------- - -----
    ---------------------------- ---
    --------------
    ----------------------
  -
  
  ---------------- -
    ----- -------------- - -------------------------- -- ----------------
    -- ---------------------- --- ---------------------- -
      --------------------- - -----
    - ---- -
      --------------------- - ------
    -
  -
-

---------------------------------- ----------

在这个组件中,我们也使用了一些事件,例如:

  • submit 事件用来触发添加操作;
  • change 事件用来触发选中状态的变化。

同时,我们在 TodoList 中也使用了 TodoItem,我们通过 TodoList 的 addItem() 函数来添加 TodoItem,并将其加入到任务列表中。

最后,在 TodoList 中我们也提供了一些属性:

  • value 属性,用于获取和设置 TodoList 的值;
  • items 属性,用于获取 TodoList 中的任务列表。
-- -------------------- ---- -------
----------------------------------------- -------- -
  ---- ---------- -
    ------ ----------------------- -- ------------------------------------
  --
  ---- --------------- -
    ----------------------------- -- -
      -- ------ -
        -------------------
      -
    ---
  -
---

----------------------------------------- -------- -
  ---- ---------- -
    ------ ---------------
  -
---

4. 使用 <todo-list> 元素

现在我们已经完成了 TodoList 的逻辑,我们可以通过以下的 HTML 来使用它:

-- -------------------- ---- -------
--------- -----
----- ----------
  ------
    ----- --------------- --
    -----------------------
    -------
      ---- - ------------ ---------- ------ ---------- ------ ----------- -
      -------- - ------- ----- -
      ------------------- ------ - -------- ------ ------- ----- -- -
      ------ - ------ ------ ------- ----- -- -
      ---- - ------ ----- -
    --------
  -------
  ------
    ----------
      -------------------------
      -----------------------
    -----------
    ----------
      ---------------------------
      --------- ------- ---------------------
      ------- ------------------------------------
    -----------
    ----------
      -----------------------
      ---- ------------------
    -----------
    ------- ---------------------------
    --------
      -------- --------- -
        ----- -- - ------------------------------------
        ----- ------ - ----------------------------------
        --- -
          ------------------ - ---------
        - ----- --- -
          ------------------ - ----------
        -
      -
    ---------
  -------
-------

这里我们通过 <todo-list> 标签来添加一个 TodoList,在某些浏览器中,我们还需要在注释中加上一些 hack,例如:

5. 示例效果

最后,我们来看一下示例的效果:

  • 添加任务:

  • 编辑任务:

  • 完成任务:

  • 删除任务:

总结

Custom Elements 可以让我们创建自定义的 HTML 元素,并在页面上使用它们,从而可以提高代码的可维护性和复用性。在本文中,我们深入介绍了 Custom Elements 的使用方法和示例,并帮助你快速构建定制化的 Web 组件。希望这篇文章对你有所帮助,谢谢阅读!

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/651cf5d095b1f8cacd47988d

纠错
反馈