Web Components 中的 Property 和 Attribute:那些坑要注意

阅读时长 14 分钟读完

Web Components 是一种用于构建可重用组件的技术,它由 Custom Elements、Shadow DOM 和 HTML Templates 三个规范组成。其中,Custom Elements 规范定义了自定义元素的创建和生命周期,而 Property 和 Attribute 则是 Custom Elements 中重要的概念。在这篇文章中,我们将深入探讨 Property 和 Attribute 的区别和联系,以及在实际使用中需要注意的一些坑。

Property 和 Attribute 的区别和联系

Property 和 Attribute 都是用于描述元素的特性的,但它们的作用和机制是不同的。

Property

Property 是元素的一个 JavaScript 属性,通过 JavaScript 可以直接访问和修改它。例如,我们可以通过以下代码获取一个 button 元素的 disabled 属性:

我们也可以通过 JavaScript 直接修改 button 元素的 disabled 属性:

在 Custom Elements 中,我们可以为自定义元素定义一个或多个 Property,通过这些 Property 可以控制元素的行为和状态。例如,我们可以为一个自定义元素定义一个 count 属性,用于记录元素被点击的次数。在 Custom Elements 的 JavaScript 构造函数中,我们可以通过 this.count 访问和修改该属性:

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

Attribute

Attribute 是元素的一个 HTML 属性,通过 HTML 可以设置和修改它。例如,我们可以通过以下 HTML 代码为一个 button 元素设置 disabled 属性:

在 Custom Elements 中,我们也可以为自定义元素定义一个或多个 Attribute,通过这些 Attribute 可以设置元素的默认值。例如,我们可以为一个自定义元素定义一个 name 属性,用于设置元素的名称。在 Custom Elements 的 JavaScript 构造函数中,我们可以通过 this.getAttribute('name') 获取该属性的值,或通过 this.setAttribute('name', value) 设置该属性的值:

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

在上面的例子中,我们使用 this.getAttribute('name') 获取 name 属性的值,并在元素的内部文本中显示出来。我们还通过 static get observedAttributes() 方法指定了需要观察的属性列表,并通过 attributeChangedCallback() 方法监听属性值的变化。

Property 和 Attribute 的同步机制

Property 和 Attribute 之间存在着一种同步机制,即当修改 Property 时,Attribute 也会同步修改;当修改 Attribute 时,Property 也会同步修改。例如,我们可以通过以下代码修改一个 button 元素的 disabled 属性:

在这个例子中,当我们修改 button.disabled 属性时,button 元素的 disabled Attribute 也会被修改。我们可以通过 button.getAttribute('disabled') 获取修改后的 Attribute 值。

同样地,我们也可以通过以下代码修改一个 button 元素的 disabled Attribute:

在这个例子中,当我们修改 button 元素的 disabled Attribute 时,button.disabled Property 也会被修改。我们可以通过 button.disabled 获取修改后的 Property 值。

需要注意的是,Property 和 Attribute 的同步机制只在 Custom Elements 中生效。对于原生元素,它们的 Property 和 Attribute 并不总是同步的。例如,当我们修改 input 元素的 value Property 时,input 元素的 value Attribute 并不会被同步修改。这种不同步的行为可能会导致一些难以调试的问题,因此在使用原生元素时需要格外小心。

Property 和 Attribute 的坑

虽然 Property 和 Attribute 的同步机制看起来很方便,但在实际使用中还是有一些坑需要注意。

Property 和 Attribute 名称的区分

在 Custom Elements 中,Property 和 Attribute 的名称必须是不同的,否则会导致一些奇怪的行为。例如,当我们为一个自定义元素定义一个名为 name 的 Property 和 Attribute 时,会出现以下问题:

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

在这个例子中,我们为一个自定义元素定义了一个名为 name 的 Property 和 Attribute。在元素的构造函数中,我们尝试访问 this.name,但它的值是 undefined。这是因为在 JavaScript 中,元素的 Property 会覆盖同名的 Attribute,因此当我们定义了一个名为 name 的 Property 时,它会覆盖原有的 name Attribute。为了避免这种问题,我们可以为 Property 和 Attribute 使用不同的名称,例如将 Property 名称改为 elementName

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

在这个例子中,我们将 Property 名称改为 elementName,并通过 get elementName()set elementName(value) 方法来访问和修改该属性。在元素的构造函数中,我们尝试访问 this.elementName,它的值是 Attribute name 的值或默认值 'World'。在 set elementName(value) 方法中,我们通过 this.setAttribute('name', value) 修改 Attribute name 的值。在 attributeChangedCallback(name, oldValue, newValue) 方法中,我们通过 this.elementName = newValue 修改 Property elementName 的值。

Property 和 Attribute 值的类型转换

在 Custom Elements 中,Property 和 Attribute 的值可能会被自动转换成不同的类型,这可能会导致一些难以调试的问题。例如,当我们为一个自定义元素定义一个名为 count 的 Property 和 Attribute 时,会出现以下问题:

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

在这个例子中,我们为一个自定义元素定义了一个名为 count 的 Property 和 Attribute。在元素的构造函数中,我们尝试访问 typeof this.counttypeof this.getAttribute('count'),它们的值分别是 'number''string'。这是因为在 JavaScript 中,元素的 Property 会被转换成 JavaScript 原生类型,而元素的 Attribute 始终是字符串类型。为了避免这种问题,我们需要在访问和修改 Property 和 Attribute 时进行类型转换,例如将 parseInt() 方法用于 Attribute 值的解析。

Property 和 Attribute 的默认值

在 Custom Elements 中,Property 和 Attribute 的默认值可能会影响元素的行为和状态。例如,当我们为一个自定义元素定义一个名为 value 的 Property 和 Attribute 时,会出现以下问题:

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

在这个例子中,我们为一个自定义元素定义了一个名为 value 的 Property 和 Attribute。在元素的构造函数中,我们尝试访问 this.valuethis.getAttribute('value'),它们的值分别是 ""null。这是因为在 Custom Elements 中,Attribute 的默认值是 null,而 Property 的默认值是一个空字符串 ""。为了避免这种问题,我们需要在访问和修改 Property 和 Attribute 时进行默认值的处理,例如将 getAttribute() 方法的返回值和 Property 的默认值进行合并。

结论

Property 和 Attribute 是 Custom Elements 中重要的概念,它们可以用于控制元素的行为和状态。在使用 Property 和 Attribute 时,我们需要注意它们的区别和联系,以及在实际使用中需要注意的一些坑。如果我们能够正确地使用 Property 和 Attribute,就可以更轻松地构建可重用的 Web 组件。

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

纠错
反馈