-->

Trying to change an element's DOM's proper

2020-05-08 08:56发布

问题:

I had a hard time phrasing that question's title, but could not find anything more concise.

I want to attach some event oninput to an element (here an input field). But for some reason it didn't work. I narrowed the issue to the schematic MWE (complete MWE at the end).

addEvent();
document.body.innerHTML += "a";

addEvent() was simply a function which changed the oninput property of an input field. My issue was that addEvent() was ignored.

To make sure addEvent(); ran normally, I also modified the value of the input field, and its backgroundColor in the body of the function. Yet, when I ran the code, the oninput and value modifications were nowhere to be found, but the backgroundColor had been modified as per the function.

More mystifying to me, if I write

document.body.innerHTML += "a";
addEvent();

Things work as expected.

My question is in two parts:

  • how to I fix the code of addEvent(), so that no matter if I write document.body.innerHTML += "a" before or after, the result would be the same?
  • why does the backgroundColor run fine, while the rest seems to be ignored?

Here is my complete MWE below:

function addEvent() {
    var fieldScore = document.getElementById("foo");
    fieldScore.style.backgroundColor = "rgb(0,255,0)";
    fieldScore.value = "a";
    fieldScore.oninput = function () {
        console.log("bar");
    }
}

// document.body.innerHTML = buildForm();
addEvent();
document.body.innerHTML += "a";
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>

<body>
    <form><input type="text" value="" name="foo" id="foo"></form>
    <script type="text/javascript" src="mwe.js"></script>
</body>

</html>

Expected: same, but with a in the input field as well.

回答1:

innerHTML += is almost always an anti-pattern. It makes the browser do this:

  • Loop through all the children and the children's children, etc., of the element on which you do it and build an HTML string.
  • Append text to that string.
  • Destroy all of those child elements (and their children, etc.), parse the HTML string, and replace them with new elements created as a result of parsing the string.

In that process, event handlers and any other non-HTML information on the elements that are destroyed is lost.

If you need to append to an element, use appendChild or insertAdjacentHTML. For instance:

document.body.appendChild(document.createTextNode("a"));

or

document.body.insertAdjacentHTML("beforeend", "a");