【问题标题】:Determining whether an attribute is valid in standard HTML (or SVG)确定属性在标准 HTML(或 SVG)中是否有效
【发布时间】:2017-11-01 07:43:51
【问题描述】:

我想在运行时以编程方式向 DOM 元素(例如 HTML 或 SVG 元素)动态添加属性,即基于用户输入。如果属性是标准属性,我将按原样使用名称,但如果不是,即如果它需要转换为自定义属性,那么我想为其添加“data-”前缀。

那么,有没有办法确定一个字符串是否代表一个“标准/正常”的 DOM 属性?

例如,假设我有一个 SVG 矩形,如下所示:

<rect x="10" y="10" width="80" height="40" stroke="black"/>

请注意,尚未(尚未)指定填充颜色。

用户请求添加两个属性:

  • 一个名为“fill”且值为“red”的属性,它应该产生fill="red"(注意没有前缀)
  • 一个名为“price”的属性,其值为“expensive”,应该产生data-price="expensive"(注意data-前缀)

如何动态区分这两者? fill 属性不存在于我当前的 DOM 元素中,因此我无法检查该名称的属性是否存在预先存在的值。我也不相信我什至可以检查如果我创建没有前缀的属性是否会引发错误,因为据我所知,至少我当前的浏览器(Chrome v61.0)将允许我添加一个属性price="expensive"(不带 data- 前缀),即使这不是最佳做法。

我想要类似下面的东西:

const elementNodeName = "rect";
const attributeName = "height"; // or, e.g. "price"
const nameIsValid = testAttributeNameValidity(elementNodeName, attributeName);
if (!nameIsValid) attributeName = 'data-' + attributeName;

是否有任何预先存在的testAttributeNameValidity-type 功能?

在寻找 Javascript 解决方案时,我已将其标记为 javascript

** 更新:其他 SO 答案的解决方案适用于 HTML,但不适用于 SVG **

基于the suggested link in the comments,我尝试使用attributeName in document.createElement(elementNodeName),它应该返回true 作为有效属性名,false 作为无效属性名。当我为 HTML 元素 (&lt;p&gt;) 使用有效的属性名称“id”时,这种方法有效。

相比之下,我还没有在 SVG 中使用这种方法。我尝试将createElement 转换为createElementNS,但这似乎仍然无法解决问题。请参阅下面的测试代码。测试代码中的关键函数是testHtmlAttributeNameValiditytestSvgAttributeNameValidity。如果您运行代码并检查控制台中的输出,它表明它可以正常用于 HTML,即它会生成 id="someId" data-price="expensive"。但是,对于 SVG,它只会产生不需要的输出:data-fill="yellow" data-price="expensive"

如果有影响,我正在使用 Chrome v61。

测试代码:

const testHtmlAttributeNameValidity = (elementNodeName, attributeName) => {
  return (attributeName in document.createElement(elementNodeName));
};

const testHtmlAttributeName = (attributeName, attributeValue) => {
  const elementNodeName = "p";
  const nameIsValid = testHtmlAttributeNameValidity(elementNodeName, attributeName);
  if (!nameIsValid) attributeName = 'data-' + attributeName;
  const element = document.querySelector(elementNodeName);
  element.setAttribute(attributeName, attributeValue);
};

testHtmlAttributeName("id", "someId");
testHtmlAttributeName("price", "expensive");

console.log(document.querySelector('div').innerHTML);


const svgNS = "http://www.w3.org/2000/svg";

const testSvgAttributeNameValidity = (elementNodeName, attributeName) => {
  return (attributeName in document.createElementNS(svgNS, elementNodeName));
};

const testSvgAttributeName = (attributeName, attributeValue) => {
  const elementNodeName = "rect";
  const nameIsValid = testSvgAttributeNameValidity(elementNodeName, attributeName);
  if (!nameIsValid) attributeName = 'data-' + attributeName;
  const element = document.querySelector(elementNodeName);
  element.setAttribute(attributeName, attributeValue);
};

testSvgAttributeName("fill", "yellow");
testSvgAttributeName("price", "expensive");

console.log(document.querySelector('svg').innerHTML);
#someId {
  color: green;
}
<svg height="55">
  <rect x="10" y="10" width="80" height="40" stroke="red"/>
</svg>

<div>
<p>Hello world</p>
</div>

正常工作的代码应该将矩形填充从黑色更改为黄色,这不会发生。

【问题讨论】:

  • 这就是制作 XHTML 的原因。然而,每个人都在为 HTML 吐口水。
  • @ShreyanshGandhi,我查看了那个链接,它似乎解决了我的问题。但是,我似乎无法实现它,如对我的问题的更新所示,其中包括不会产生所需结果的测试代码。此外,我尝试将标准的createElement 用于 HTML,但也尝试使用更具体的createElementNS 用于 svg...都没有奏效。
  • @ShreyanshGandhi,进一步更新:我在 HTML 中的非工作尝试似乎与我使用属性名称“class”有关,在某些情况下,它应该是“className”。如果我使用属性名称“id”,则链接中的解决方案可以解决问题。但是,即使我使用createElementNS,我仍然无法让它与 SVG 一起使用。
  • 一些 SVG 属性是presentation attributes。其中一些可能具有相应的属性,但大多数可能被视为写为属性的 CSS 样式。它们可以作为 Element.style 界面上的属性找到(如果您发现浏览器不一致和错误的方法)。但是由于这个对象包含 所有 CSS 属性的名称,因此无法通过这种方式判断它们是否也可以用作 SVG 属性。

标签: javascript html svg attributes


【解决方案1】:

@ccprog 的评论帮助我解决了这个问题。总而言之,对于 SVG DOM 元素,我需要原始检查加上一个相同的布尔或运算检查,但添加了 .style 属性。

如题所示,一个HTML DOM元素属性名的有效性可以通过如下检查来判断:

// correct for HTML:
return (
  attributeName in document.createElement(elementNodeName)
);

但是,这种方法不适用于 SVG DOM 元素。具体来说,以下确定“id”之类的真实属性名称的有效性,但确定“fill”之类的样式属性名称的有效性:

// insufficient for SVG, i.e. only partially correct:
return (
  attributeName in document.createElementNS(svgNS, elementNodeName)
);

但是,只需复制该测试并将 .style 属性添加到两个检查之一,就可以检查两个类别的属性名称,如下所示:

// correct for SVG:
return (
  attributeName in document.createElementNS(svgNS, elementNodeName).style ||
  attributeName in document.createElementNS(svgNS, elementNodeName)
);

这在以下代码中得到了证明,除了上述更改之外,它与问题中的代码基本相同。确定两个属性名称类别有效性的能力反映在可见矩形中黄色填充和粗笔画宽度的外观上,同时向元素添加自定义“data-price”属性。请特别注意 HTML DOM 元素和 SVG DOM 元素需要以不同方式进行检查。

const testHtmlAttributeNameValidity = (elementNodeName, attributeName) => {
  return (attributeName in document.createElement(elementNodeName));
  return (
    attributeName in document.createElement(elementNodeName)
  );
};

const testHtmlAttributeName = (attributeName, attributeValue) => {
  const elementNodeName = "p";
  const nameIsValid = testHtmlAttributeNameValidity(elementNodeName, attributeName);
  if (!nameIsValid) attributeName = 'data-' + attributeName;
  const element = document.querySelector(elementNodeName);
  element.setAttribute(attributeName, attributeValue);
};

testHtmlAttributeName("id", "someHtmlId");
  // This should result in "id" attribute being changed, changing the
  // font color to green.

testHtmlAttributeName("color", "orange");
  // While "color" IS a CSS property name, it is NOT an HTML DOM element
  // attribute name. Therefore, this test should result in "color" NOT being
  // recognized as a valid attribute name, resulting in the
  // custom attribute name "data-color", with no effect on the
  // actual styling of the element, i.e. this test should NOT
  // turn the text orange. This test is included here
  // to provide a contrast to what should happen with SVG DOM
  // element style-like attributes like "fill", as shown below
  // in the section testing SVG DOM element attribute names.

testHtmlAttributeName("price", "expensive");
  // This should result in a new attribute with the name "data-price"
  // and the value "expensive".

console.log(document.querySelector('div').innerHTML);


const svgNS = "http://www.w3.org/2000/svg";

const testSvgAttributeNameValidity = (elementNodeName, attributeName) => {
  return ( // ********** THIS IS THE IMPORTANT CHANGE **********
    attributeName in document.createElementNS(svgNS, elementNodeName).style ||
    attributeName in document.createElementNS(svgNS, elementNodeName)
  );
};

const testSvgAttributeName = (attributeName, attributeValue) => {
  const elementNodeName = "rect";
  const nameIsValid = testSvgAttributeNameValidity(elementNodeName, attributeName);
  if (!nameIsValid) attributeName = 'data-' + attributeName;
  const element = document.querySelector(elementNodeName);
  element.setAttribute(attributeName, attributeValue);
};

testSvgAttributeName("id", "someSvgId");
testSvgAttributeName("fill", "yellow"); // *** Now correctly identified as valid
testSvgAttributeName("price", "expensive");

console.log(document.querySelector('svg').innerHTML);
#someHtmlId {
  color: green;
}
#someSvgId {
  stroke-width: 5px;
}
<svg height="55">
  <rect x="10" y="10" width="80" height="40" stroke="red"/>
</svg>

<div>
<p>Hello world</p>
</div>

【讨论】:

    猜你喜欢
    • 2022-08-19
    • 1970-01-01
    • 2014-05-28
    • 2014-10-21
    • 2014-09-29
    • 2012-05-17
    • 1970-01-01
    • 2019-02-22
    • 1970-01-01
    相关资源
    最近更新 更多