确定属性在标准HTML(或SVG)中是否有效

时间:2017-09-25 17:04:08

标签: javascript html svg attributes

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

那么,有没有办法确定字符串是否代表“标准/普通”DOM属性?

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

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

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

用户请求添加两个属性:

  • 名为“fill”的属性,其值为“red”,应该会产生fill="red"(请注意没有前缀)
  • 名为“price”的属性,其值为“昂贵”,应该会产生data-price="expensive"(请注意data-前缀)

如何动态区分这两者?我当前的DOM元素中不存在fill属性,因此我无法检查该名称的属性是否存在预先存在的值。如果我创建没有前缀的属性,我也不相信我甚至可以检查是否会引发错误,因为据我所知,至少我当前的浏览器(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类型功能吗?

我用javascript标记了这一点,因为我正在寻找一个Javascript解决方案。

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

根据the suggested link in the comments,我尝试使用attributeName in document.createElement(elementNodeName),它应该返回true表示有效的属性名称,false表示无效的属性名称。当我为HTML元素(<p>)使用有效的属性名称“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>

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

1 个答案:

答案 0 :(得分:0)

@ccprog的评论帮助我解决了这个问题。总之,对于SVG DOM元素,我需要原始检查加上一个布尔-OR&#d检查,它是相同的,但添加了.style属性。

如问题所示,HTML DOM元素属性名称的有效性可通过以下方式确定:

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

但是,这种方法不适用于SVG DOM元素。具体来说,以下确定真实属性名称的有效性,例如&#34; id&#34;,但将确定样式属性名称的有效性,例如& #34;填充&#34;:

// 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)
);

以下代码对此进行了演示,除了上述更改之外,该代码与问题中的代码基本相同。确定两类属性名称有效性的能力反映在可见矩形中黄色填充和粗笔划宽度的外观上,同时添加自定义&#34;数据价格&#34;属性为元素。请特别注意HTML DOM元素和SVG DOM元素需要以不同方式进行检查。

&#13;
&#13;
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);
&#13;
#someHtmlId {
  color: green;
}
#someSvgId {
  stroke-width: 5px;
}
&#13;
<svg height="55">
  <rect x="10" y="10" width="80" height="40" stroke="red"/>
</svg>

<div>
<p>Hello world</p>
</div>
&#13;
&#13;
&#13;