使用 JavaScript,是否可以获得浏览器支持的标签列表?
4 回答
您可以对窗口内省所支持的内容有一个不错的了解。
试试这个:
props = Object.getOwnPropertyNames(window)
for (var idx in props) {
if (props[idx].indexOf("HTML") == 0) {
//do something here
console.log(props[idx]);
}
}
据我所知,这绝不是详尽无遗的,但它会在大多数浏览器中告诉您哪些标签具有 DOM 对象类型。
这是在我的 Chrome 控制台中运行的示例输出:
HTMLUnknownElement
HTMLOptionsCollection
HTMLFormControlsCollection
HTMLAllCollection
HTMLCollection
HTMLUListElement
HTMLTitleElement
HTMLTextAreaElement
HTMLTemplateElement
HTMLTableSectionElement
HTMLTableRowElement
HTMLTableElement
HTMLTableColElement
HTMLTableCellElement
HTMLTableCaptionElement
HTMLStyleElement
HTMLSpanElement
HTMLSelectElement
HTMLScriptElement
HTMLQuoteElement
HTMLProgressElement
HTMLPreElement
HTMLParamElement
HTMLParagraphElement
HTMLOutputElement
HTMLOptionElement
HTMLOptGroupElement
HTMLObjectElement
HTMLOListElement
HTMLModElement
HTMLMeterElement
HTMLMetaElement
HTMLMenuElement
HTMLMarqueeElement
HTMLMapElement
HTMLLinkElement
HTMLLegendElement
HTMLLabelElement
HTMLLIElement
HTMLKeygenElement
HTMLInputElement
HTMLImageElement
HTMLIFrameElement
HTMLHtmlElement
HTMLHeadingElement
HTMLHeadElement
HTMLHRElement
HTMLFrameSetElement
HTMLFrameElement
HTMLFormElement
HTMLFontElement
HTMLFieldSetElement
HTMLEmbedElement
HTMLDivElement
HTMLDirectoryElement
HTMLDataListElement
HTMLDListElement
HTMLCanvasElement
HTMLButtonElement
HTMLBodyElement
HTMLBaseElement
HTMLBRElement
HTMLAreaElement
HTMLAppletElement
HTMLAnchorElement
HTMLElement
HTMLDocument
如果您愿意从已知的候选标签列表开始,您可以尝试这样的事情:
document.createElement("asdf") instanceof HTMLUnknownElement
true
document.createElement("canvas") instanceof HTMLUnknownElement
false
如果你需要支持 IE8,你可以使用这种方法:
function browserSupports(elementTagName) {
var el = document.createElement(elementTagName);
return !((el instanceOf HTMLUnknownElement) || (el instanceof HTMLGenericElement));
}
这是另一种不依赖特定命名构造函数的方法。
function browserSupports(elementTagName) {
var unknownel = document.createElement("zzxcv");
var el = document.createElement(elementTagName);
return unknownel.constructor !== el.constructor;
}
不过,它似乎仍然无法在 IE8 中工作。
每个由document.createElement()创建的JavaScript html元素对象都有一个构造函数,它总是以“HTML...”开头并以“...Element”结尾。所有这些都继承自 HTMLElement。这些中的每一个都可以通过Object.getOwnPropertyNames()在窗口对象中访问。
因此,您可以通过遍历 window 中的所有属性名称并使用HTML...ELement过滤它们来获取所有有效的标签名称:
function getAllTagNames()
{
let names = [];
Object.getOwnPropertyNames(window).forEach(name =>
{
if(name.startsWith('HTML') && name.endsWith('Element') && Object.getPrototypeOf(window[name]) == HTMLElement)
{
names.push(name.substr(4, name.length - 11).toLowerCase());
}
});
names.sort((left, right) =>
{
if(left.toLowerCase) { left = left.toLowerCase(); }
if(right.toLowerCase) { right = right.toLowerCase(); }
return left == right ? 0 : (left < right ? -1 : 1);
});
return names;
}
如何使用它:
console.log(getAllTagNames()); // [anchor", "area", "base", "body", "br", ...]
编辑
html 元素的一些构造函数只是基本构造函数(例如HTMLMediaElement)。在这种情况下,HTMLAudioElement ( <audio></audio> ) 和HTMLVideoElement ( <video></video> ) 的基本构造函数不是直接继承自HTMLElement。所以需要遍历完整的原型链,instanceof操作符适合这个:
window['HTMLAudioElement'].prototype instanceof HTMLElement
另一方面是某些构造函数名称不适合等效的 html 标记名称(< a > => HTML锚元素),而其他一些名称适合多个标记(例如<h1></h1>、<h2></ h2>, <h3></h3>, <h4></h4>, <h5></h5>, <h6></h6> ) 具有相同的构造函数。> 见 mdn。
目前在 JavScript 中没有其他方法可以使用 document.createElement(tagName); 创建错误的标识标签名称,请检查构造函数是否为 HTMLUnknownElement 并手动修复这些:
function getAllTagNames()
{
let items = [];
Object.getOwnPropertyNames(window).forEach(name =>
{
if(name.startsWith('HTML') && name.endsWith('Element') && window[name].prototype instanceof HTMLElement)
{
items.push({ constructorName: name, tagName: name.substr(4, name.length - 11).toLowerCase() });
}
});
items.sort((leftItem, rightItem) =>
{
let left = leftItem.tagName;
let right = rightItem.tagName;
if(left.toLowerCase) { left = left.toLowerCase(); }
if(right.toLowerCase) { right = right.toLowerCase(); }
return left == right ? 0 : (left < right ? -1 : 1);
});
function insertSorted(item)
{
let index = 0;
while(item.tagName > items[index].tagName) { index++; }
items.splice(index, 0, item);
}
let disagreements = [];
items = items.filter(item =>
{
let tagName = item.tagName;
switch(tagName) // deprecated
{
case "keygen": return false;
}
let filter = tagName == "unknown" || document.createElement(tagName).constructor == HTMLUnknownElement;
if(filter && tagName != "unknown") { disagreements.push(item); }
return !filter;
});
disagreements = disagreements.filter(item =>
{
switch(item.tagName) // base constructor
{
case "media": return false;
}
return true;
});
disagreements.forEach(item =>
{
let tagName = item.tagName;
function exchange(tagName)
{
insertSorted({ constructorName: item.constructorName, tagName: tagName });
}
switch(tagName)
{
case 'anchor':
exchange('a');
break;
case 'directory':
exchange('dir');
break;
case 'dlist':
exchange('dl');
break;
case 'heading':
exchange('h1');
exchange('h2');
exchange('h3');
exchange('h4');
exchange('h5');
exchange('h6');
break;
case 'image':
exchange('img');
break;
case 'mod':
exchange('del');
exchange('ins');
break;
case 'olist':
exchange('ol');
break;
case 'paragraph':
exchange('p');
break;
case 'quote':
exchange('blockquote');
exchange('q');
break;
case 'tablecaption':
exchange('caption');
break;
case 'tablecell':
exchange('th');
exchange('td');
break;
case 'tablecol':
exchange('col');
exchange('colgroup');
break;
case 'tablerow':
exchange('tr');
break;
case 'tablesection':
exchange('tfoot');
exchange('thead');
exchange('tbody');
break;
case 'ulist':
exchange('ul');
break;
default:
console.log('disagree', tagName);
if(console.warn && tagName != "") { console.warn("unknown tag name for " + item.constructorName); }
break;
}
});
return items.map(item => item.tagName);
}
编辑2:
let tagNames =
[
{ name: "a", constr: "HTMLAnchorElement" },
{ name: "area", constr: "HTMLAreaElement" },
{ name: "audio", constr: "HTMLAudioElement" },
{ name: "base", constr: "HTMLBaseElement" },
{ name: "body", constr: "HTMLBodyElement" },
{ name: "br", constr: "HTMLBRElement" },
{ name: "button", constr: "HTMLButtonElement" },
{ name: "canvas", constr: "HTMLCanvasElement" },
{ name: "content", constr: "HTMLContentElement" },
{ name: "data", constr: "HTMLDataElement" },
{ name: "datalist", constr: "HTMLDataListElement" },
{ name: "details", constr: "HTMLDetailsElement" },
{ name: "dialog", constr: "HTMLDialogElement" },
{ name: "dir", constr: "HTMLDirectoryElement" },
{ name: "div", constr: "HTMLDivElement" },
{ name: "dl", constr: "HTMLDListElement" },
{ name: "embed", constr: "HTMLEmbedElement" },
{ name: "fieldset", constr: "HTMLFieldSetElement" },
{ name: "font", constr: "HTMLFontElement" },
{ name: "form", constr: "HTMLFormElement" },
{ name: "frame", constr: "HTMLFrameElement" },
{ name: "frameset", constr: "HTMLFrameSetElement" },
{ name: "head", constr: "HTMLHeadElement" },
{ name: "h1", constr: "HTMLHeadingElement" },
{ name: "h2", constr: "HTMLHeadingElement" },
{ name: "h3", constr: "HTMLHeadingElement" },
{ name: "h4", constr: "HTMLHeadingElement" },
{ name: "h5", constr: "HTMLHeadingElement" },
{ name: "h6", constr: "HTMLHeadingElement" },
{ name: "hr", constr: "HTMLHRElement" },
{ name: "html", constr: "HTMLHtmlElement" },
{ name: "iframe", constr: "HTMLIFrameElement" },
{ name: "img", constr: "HTMLImageElement" },
{ name: "input", constr: "HTMLInputElement" },
{ name: "label", constr: "HTMLLabelElement" },
{ name: "legend", constr: "HTMLLegendElement" },
{ name: "li", constr: "HTMLLIElement" },
{ name: "link", constr: "HTMLLinkElement" },
{ name: "map", constr: "HTMLMapElement" },
{ name: "marquee", constr: "HTMLMarqueeElement" },
{ name: "menu", constr: "HTMLMenuElement" },
{ name: "meta", constr: "HTMLMetaElement" },
{ name: "meter", constr: "HTMLMeterElement" },
{ name: "del", constr: "HTMLModElement" },
{ name: "ins", constr: "HTMLModElement" },
{ name: "object", constr: "HTMLObjectElement" },
{ name: "ol", constr: "HTMLOListElement" },
{ name: "optgroup", constr: "HTMLOptGroupElement" },
{ name: "option", constr: "HTMLOptionElement" },
{ name: "output", constr: "HTMLOutputElement" },
{ name: "p", constr: "HTMLParagraphElement" },
{ name: "param", constr: "HTMLParamElement" },
{ name: "picture", constr: "HTMLPictureElement" },
{ name: "pre", constr: "HTMLPreElement" },
{ name: "progress", constr: "HTMLProgressElement" },
{ name: "q", constr: "HTMLQuoteElement" },
{ name: "script", constr: "HTMLScriptElement" },
{ name: "select", constr: "HTMLSelectElement" },
{ name: "shadow", constr: "HTMLShadowElement" },
{ name: "slot", constr: "HTMLSlotElement" },
{ name: "source", constr: "HTMLSourceElement" },
{ name: "span", constr: "HTMLSpanElement" },
{ name: "style", constr: "HTMLStyleElement" },
{ name: "td", constr: "HTMLTableCellElement" },
{ name: "th", constr: "HTMLTableCellElement" },
{ name: "col", constr: "HTMLTableColElement" },
{ name: "colgroup", constr: "HTMLTableColElement" },
{ name: "table", constr: "HTMLTableElement" },
{ name: "tr", constr: "HTMLTableRowElement" },
{ name: "tbody", constr: "HTMLTableSectionElement" },
{ name: "tfoot", constr: "HTMLTableSectionElement" },
{ name: "thead", constr: "HTMLTableSectionElement" },
{ name: "template", constr: "HTMLTemplateElement" },
{ name: "time", constr: "HTMLTimeElement" },
{ name: "title", constr: "HTMLTitleElement" },
{ name: "track", constr: "HTMLTrackElement" },
{ name: "ul", constr: "HTMLUListElement" },
{ name: "video", constr: "HTMLVideoElement" }
];
没有通用的方法,但每个元素都有特定的方法来查看它是否受支持
画布元素支持:
var canvasSupported = "getContext" in document.createElement("canvas");
输入类型支持:
var input = document.createElement("input");
input.type = "color"
var colorInputSupported = input.type === "color";
//The above relies on the fact that type is enumerated and
//falls back to "text" with invalid value
//The technique doesn't necessarily carry over to other properties
音频元素支持:
var audioElementSupported = "play" in document.createElement("audio");
进度元素支持
var progressElementSupported = "max" in document.createElement("progress");