【问题标题】:Clarifying the status of custom attributes in HTML Custom Elements in WebComponents澄清 WebComponents 中 HTML 自定义元素中自定义属性的状态
【发布时间】:2021-01-26 16:16:53
【问题描述】:

直到最近,每当我需要在我的 HTML 中使用自定义属性时,我总是使用 HTML5 data-* 自定义属性

最近开始尝试WebComponents,特别是自定义元素,我开始考虑不是 HTML5 的自定义属性data-* 自定义属性。

在无意中采用任何不推荐的做法之前,我想澄清以下几点......

在下面的列表中,我们有 4 个元素:

  • 元素 i 是具有data-* 属性的标准元素
  • 元素 ii 是具有自定义属性的标准元素
  • 元素 iii 是具有 data-* 属性的自定义元素
  • Element iv 是具有自定义属性的自定义元素

const toggleDataAttribute = (e) => {
    e.target.dataset.inverted = (e.target.dataset.inverted === 'true') ? 'false' : 'true';
}

const toggleCustomAttribute = (e) => {
  if (e.target.getAttribute('inverted') === 'true') {
    e.target.setAttribute('inverted', 'false');
  }

  else {
    e.target.setAttribute('inverted', 'true');
  }
}

const toggleInvert = (e) => {

  if (e.target.dataset.inverted) {
    toggleDataAttribute(e);
  }
  
  else {
    toggleCustomAttribute(e);
  }
}


// Attach click event TO <div> elements
let divs = [...document.getElementsByTagName('div')];

divs.forEach((div) => div.addEventListener('click', toggleInvert, false));

// Attach click event TO <my-circle> elements
let myCircles = [...document.getElementsByTagName('my-circle')];

myCircles.forEach((myCircle) => myCircle.addEventListener('click', toggleInvert, false));


// Define <my-circle> element
class myCircle extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {
    this.root.appendChild(document.createElement('slot'));
  }
}

customElements.define('my-circle', myCircle);
aside {
  position: absolute;
  top: 0;
  right: 0;
  width: 280px;
  line-height: 24px;
}

div {
  float: left;
  margin: 0 12px 12px 0;
  width: 80px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  font-size: 36px;
  border-radius: 50%;
  cursor: pointer;
}

my-circle {
  display: block;
  float: left;
  margin: 0 12px 12px 0;
  width: 80px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  font-size: 36px;
  background: radial-gradient(#fff, #000);
  border-radius: 50%;
  cursor: pointer;
}

my-circle:first-of-type {
  clear: left;
}


div:nth-of-type(1) {
  background: radial-gradient(rgb(255, 255, 0), rgb(255, 0, 0));
}

div:nth-of-type(2) { 
  background: radial-gradient(rgb(255, 255, 0), rgb(0, 163, 0));
}

my-circle:nth-of-type(1) { 
  background: radial-gradient(rgb(255, 255, 0), rgb(223, 163, 0));
}

my-circle:nth-of-type(2) {
  background: radial-gradient(rgb(255, 127, 127), rgb(255, 0, 0));
}

div[data-inverted="true"],
div[inverted="true"],
my-circle[data-inverted="true"],
my-circle[inverted="true"] {
  filter: hue-rotate(180deg);
}
<div data-inverted="false">i</div>
<div inverted="false">ii</div>

<my-circle data-inverted="false">iii</my-circle>
<my-circle inverted="false">iv</my-circle>

<aside>
<p><strong>Click</strong> on each of the circles on the left to invert their backgrounds.</p>
</aside>

虽然上述设置在技术上有效,但以下哪项是正确的:

  • A) 自定义属性可以在标准元素和自定义元素中普遍使用。

    • 结论:元素iiiiiiiv都是有效的
  • B) 自定义属性只能用于自定义元素。它们在其他地方无效。

    • 结论:元素iiiiiv有效,而ii无效
  • C) Data-* 属性用于标准元素,自定义属性用于自定义元素。

    • 结论:元素i & iv有效,ii & iii无效
  • D) 自定义属性甚至不是一回事。你是从哪里得到这个想法的?

    • 结论:元素i & iii有效,ii & iv无效

补充:

为了说明我上面的问题,我想举一个例子说明自定义属性似乎无效:

  1. 转至:https://validator.w3.org/nu/#textarea

  2. 选择文本输入

  3. 输入:

<!DOCTYPE html>
<html lang="">
<head>
<title>Test</title>
</head>
<body>

<div data-inverted="false">i</div>

<div inverted="false">ii</div>

</body>
</html>
  1. 检查标记

验证器返回错误:

错误:此时元素div 上不允许使用属性inverted

从第 10 行第 1 列开始;到第 10 行第 22 列

i&lt;/div&gt;↩↩&lt;div inverted="false"&gt;ii&lt;/di

虽然...我不确定https://validator.w3.org/nu/ 的工具是否已过时和/或被放弃,返回的 Error 不应再被视为 2020 年的错误(?)

【问题讨论】:

    标签: web-component custom-element native-web-component html5-data


    【解决方案1】:

    所有 4 种用法都有效,为什么它们应该是无效的?

    data- 前缀提供了添加的奖励,它们在element.dataset 中可用。

    -- Attributes are Attributes -- ,在自定义元素 API 中没什么特别的,
    除了observedAttributes()。是的,您可以在那里使用data-* 属性。

    注意

    class myCircle extends HTMLElement {
      constructor() {
        super();
        this.root = this.attachShadow({mode: "open"});
      }
      connectedCallback() {
        this.root.appendChild(document.createElement('slot'));
      }
    }
    

    可以写成:

    class myCircle extends HTMLElement {
      constructor() {
        super()
          .attachShadow({mode: "open"})
          .append(document.createElement('slot'));
      }
    }
    

    因为 super() 返回 'this'
    attachShadow setsreturns this.shadowRoot 免费
    你没有对appendChild() 返回值做任何事情,所以append()可以接受多个参数)就足够了。

    还要注意有一个toggleAttribute 方法。

    【讨论】:

    • 感谢@Danny - 非常感谢。 .toggleAttribute() 仅适用于布尔属性,我认为,(是的,你是对的,我 确实 在我的示例中使用了布尔值的字符串等价物,但这可能过于简单化了)。我注意到你关于attachShadow() 返回this.shadowRoot 的精彩观点。关于有效性 - 浏览器通常会接受各种无效和不推荐使用的标记当然是这样的,因此在浏览器中工作的东西并不能(对我来说,无论如何)足以保证使用是有效的根据HTML5 规范。
    • 自定义元素并不是什么新鲜事。它允许我们普通的开发人员扩展 HMLElement(以前只有浏览器供应商可以在他们的代码中做的事情)因此来自 HTMLElement(过去 25 年以上)的所有“属性”都适用。 -- (Apple 不会实现 Customized Built-In 元素,所以从 HTMLElement 扩展是我们在 Safari 中得到的全部)
    • 找到this on UnknownElements 恕我直言,它也适用于“属性”。 Quote: 验证器非常适合不熟悉 HTML 并需要指导的人。如果您愿意从规范和浏览器实现中获得指导,那么没有理由担心被验证器失败。这绝对是一件可以做的事情,只要你有意识地这样做并且你对自己在做什么有足够的了解。
    • 是的,措辞有点奇怪...html.spec.whatwg.org/multipage/syntax.html#attributes-2属性名称必须包含一个或多个字符,而不是:SPACE "'> , / =
    猜你喜欢
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2019-08-12
    相关资源
    最近更新 更多