hasAttribute("Role") 崩溃网页
hasAttribute("Role") crashing web page
我正在创建一个 JavaScript Bookmarklet,它检查每个 div 元素以查看它是否具有角色属性,以及检查“onkeypress”和“onclick”属性。它突出显示 div 没有角色或具有“onclick”且缺少“onkeypress”的。
我在检查角色属性的 if 语句中遇到问题。下面的代码会导致使用它的任何页面崩溃。
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++){
if(divs[i].hasAttribute("role")){
if(divs[i].hasAttribute("onclick" || "onClick")){
if(!divs[i].hasAttribute("onkeypress")){
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
divs[i].appendChild(divAbove);
}
}
}else{
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
divs[i].appendChild(divAbove);
}
}
但是每当我在检查“onclick”的 if 语句中添加用于检查角色的 if 语句时,它不再崩溃。但这删除了检查每个 div 角色的功能。
我不确定问题出在哪里。我将不胜感激任何帮助。谢谢。
这里的问题是 getElementsByTagName()
returns a HTMLCollection
.
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
因此,当您创建新的 div 时,集合会发生变化。这会导致无限迭代,因为您也迭代了新的 div
。
为避免这种情况,您可以使用未直播的 querySelectorAll()
。
const divs = document.querySelectorAll("div");
for(var i = 0; i < divs.length; i++){
if(divs[i].hasAttribute("role")){
if(divs[i].hasAttribute("onclick") || divs[i].hasAttribute("onClick")){
if(!divs[i].hasAttribute("onkeypress")){
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
divs[i].appendChild(divAbove);
}
}
}else{
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
divs[i].appendChild(divAbove);
}
}
<div></div>
<div></div>
<div></div>
<div></div>
.forEach()
在这里不是必需的,但可能比 for 循环更简洁。
const divs = document.querySelectorAll("div");
divs.forEach(div => {
if (div.hasAttribute("role")) {
if (div.hasAttribute("onclick") || div.hasAttribute("onClick")) {
if (!div.hasAttribute("onkeypress")) {
div.classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
div.appendChild(divAbove);
}
}
} else {
div.classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
div.appendChild(divAbove);
}
});
<div></div>
<div></div>
<div></div>
<div></div>
如评论中所述,将 .hasAttribute("onclick" || "onClick")
替换为 divs[i].hasAttribute("onclick") || divs[i].hasAttribute("onClick")
。
正如@Sven Eberth 指出的那样,您的 div collection 已上线。但是你可以通过复制来冻结它。在您的代码中让我印象深刻的是您的 3 级嵌套非常丑陋(对此感到抱歉)条件语句。请考虑在一些辅助方法上更改此条件。
var divs = Array.from(document.getElementsByTagName("div"));
const elementAttribute = (attributes, element) => {
return attributes.include.every(attr => element.hasAttribute(attr))
&& attributes.exclude.every(attr => !element.hasAttribute(attr))
}
const createElement = ({classList, html}) => {
const divAbove = document.createElement("div");
classList.forEach(className => divAbove.classList.add(className));
divAbove.innerHTML = html;
return divAbove;
}
const insertElement = ({parent, parentClassNames}, attrs) => {
parent.classsList.add(parentClassNames);
element = createElement(attrs);
parent.appendChild(element);
}
for(var i = 0; i < divs.length; i++){
if(elementAttribute({
include: ["role", "onclick"],
exclude: ["onkeypress"]
}, divs[i]){
insertElement(
{parent: divs[i], parentClassNames: "highlight"},
{classNames: "text-box", html: "Div"}
)
} else{
insertElement(
{parent: divs[i], parentClassNames: "highlight"},
{classNames: "text-box", html: "Div: Lacks Role"}
)
}
}
p.s。 onclick 与 onClick:
Html 元素属性不区分大小写。保持 HTML 标记小写的好习惯。所以你不必检查是否存在“onClick”或“onclick”。更多带有大写字母的 onClick 是反应内部处理程序。它永远不会作为属性添加到 html 元素。
证明:
无论您勾选“onclick”还是“onClick”,都以相同的方式处理。
const divs = Array.from(document.getElementsByTagName("div"))
const divsWith_onClick = divs.filter(el => el.hasAttribute("onClick"));
const divsWith_onclick = divs.filter(el => el.hasAttribute("onclick"));
console.log(divsWith_onClick.length === divsWith_onclick.length)
<div onClick="()=>{}"/>
<div onclick="()=>{}"/>
我正在创建一个 JavaScript Bookmarklet,它检查每个 div 元素以查看它是否具有角色属性,以及检查“onkeypress”和“onclick”属性。它突出显示 div 没有角色或具有“onclick”且缺少“onkeypress”的。
我在检查角色属性的 if 语句中遇到问题。下面的代码会导致使用它的任何页面崩溃。
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++){
if(divs[i].hasAttribute("role")){
if(divs[i].hasAttribute("onclick" || "onClick")){
if(!divs[i].hasAttribute("onkeypress")){
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
divs[i].appendChild(divAbove);
}
}
}else{
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
divs[i].appendChild(divAbove);
}
}
但是每当我在检查“onclick”的 if 语句中添加用于检查角色的 if 语句时,它不再崩溃。但这删除了检查每个 div 角色的功能。
我不确定问题出在哪里。我将不胜感激任何帮助。谢谢。
这里的问题是 getElementsByTagName()
returns a HTMLCollection
.
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
因此,当您创建新的 div 时,集合会发生变化。这会导致无限迭代,因为您也迭代了新的 div
。
为避免这种情况,您可以使用未直播的 querySelectorAll()
。
const divs = document.querySelectorAll("div");
for(var i = 0; i < divs.length; i++){
if(divs[i].hasAttribute("role")){
if(divs[i].hasAttribute("onclick") || divs[i].hasAttribute("onClick")){
if(!divs[i].hasAttribute("onkeypress")){
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
divs[i].appendChild(divAbove);
}
}
}else{
divs[i].classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
divs[i].appendChild(divAbove);
}
}
<div></div>
<div></div>
<div></div>
<div></div>
.forEach()
在这里不是必需的,但可能比 for 循环更简洁。
const divs = document.querySelectorAll("div");
divs.forEach(div => {
if (div.hasAttribute("role")) {
if (div.hasAttribute("onclick") || div.hasAttribute("onClick")) {
if (!div.hasAttribute("onkeypress")) {
div.classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div";
div.appendChild(divAbove);
}
}
} else {
div.classList.add("highlight");
var divAbove = document.createElement("div");
divAbove.classList.add("text-box");
divAbove.innerHTML = "Div: Lacks Role";
div.appendChild(divAbove);
}
});
<div></div>
<div></div>
<div></div>
<div></div>
如评论中所述,将 .hasAttribute("onclick" || "onClick")
替换为 divs[i].hasAttribute("onclick") || divs[i].hasAttribute("onClick")
。
正如@Sven Eberth 指出的那样,您的 div collection 已上线。但是你可以通过复制来冻结它。在您的代码中让我印象深刻的是您的 3 级嵌套非常丑陋(对此感到抱歉)条件语句。请考虑在一些辅助方法上更改此条件。
var divs = Array.from(document.getElementsByTagName("div"));
const elementAttribute = (attributes, element) => {
return attributes.include.every(attr => element.hasAttribute(attr))
&& attributes.exclude.every(attr => !element.hasAttribute(attr))
}
const createElement = ({classList, html}) => {
const divAbove = document.createElement("div");
classList.forEach(className => divAbove.classList.add(className));
divAbove.innerHTML = html;
return divAbove;
}
const insertElement = ({parent, parentClassNames}, attrs) => {
parent.classsList.add(parentClassNames);
element = createElement(attrs);
parent.appendChild(element);
}
for(var i = 0; i < divs.length; i++){
if(elementAttribute({
include: ["role", "onclick"],
exclude: ["onkeypress"]
}, divs[i]){
insertElement(
{parent: divs[i], parentClassNames: "highlight"},
{classNames: "text-box", html: "Div"}
)
} else{
insertElement(
{parent: divs[i], parentClassNames: "highlight"},
{classNames: "text-box", html: "Div: Lacks Role"}
)
}
}
p.s。 onclick 与 onClick:
Html 元素属性不区分大小写。保持 HTML 标记小写的好习惯。所以你不必检查是否存在“onClick”或“onclick”。更多带有大写字母的 onClick 是反应内部处理程序。它永远不会作为属性添加到 html 元素。
证明: 无论您勾选“onclick”还是“onClick”,都以相同的方式处理。
const divs = Array.from(document.getElementsByTagName("div"))
const divsWith_onClick = divs.filter(el => el.hasAttribute("onClick"));
const divsWith_onclick = divs.filter(el => el.hasAttribute("onclick"));
console.log(divsWith_onClick.length === divsWith_onclick.length)
<div onClick="()=>{}"/>
<div onclick="()=>{}"/>