Javascript 注入html会更改元素的属性';s保存的实例

Javascript 注入html会更改元素的属性';s保存的实例,javascript,Javascript,当我尝试将原始html注入文档主体时,一个已保存的元素实例将通过.querySelector()检索突然重置其.clientHeight和.clientWidth属性 下一页显示了该问题 <head> <script> window.addEventListener('load', pageInit); function pageInit() { // saving instance for later use var

当我尝试将原始html注入文档主体时,一个已保存的元素实例将通过
.querySelector()检索突然重置其.clientHeight和.clientWidth属性

下一页显示了该问题

<head>

<script>
    window.addEventListener('load', pageInit);

    function pageInit() {
        // saving instance for later use
        var element = document.querySelector('#element')

        alert(element.clientHeight);   // returns 40

        document.querySelector('body').innerHTML += '<p>anything</p>';

        alert(document.querySelector('#element').clientHeight);  // returns 40
        alert(element.clientHeight);  // returns 0
    }
</script>

<style>
    #element {
        height: 40px;
    }
</style>
</head>

<body>

    <div id="element"></div>

</body>

window.addEventListener('load',pageInit);
函数pageInit(){
//保存实例以供以后使用
var element=document.querySelector(“#element”)
alert(element.clientHeight);//返回40
document.querySelector('body').innerHTML+=';
alert(document.querySelector('#element').clientHeight);//返回40
警报(element.clientHeight);//返回0
}
#元素{
高度:40px;
}
为什么元素变量的实例属性会被重置?
正如在这个问题中所指出的,eventListeners被分离,但这仍然不能解释为什么元素节点仍然存在,以及为什么它的属性被置零。

当您重置
主体
元素的
innerHTML
时,您似乎正在导致整个页面被重新呈现。因此,页面上显示的
div#元素
与JavaScript变量
元素
指向的元素不同;相反,您看到的是在重新呈现页面时创建的新元素。但是,
元素
指向的
div#元素
仍然存在;它还没有被浏览器的垃圾收集器破坏

为了证明这一点,请尝试用
console.log(element)
替换上一个警报(向0发出警报的警报),然后尝试单击console窗口中的元素。您将看到
,但当您单击它时,什么也不会发生,因为div不在页面上

相反,您希望执行以下操作:

const newEl = document.createElement('p');
newEl.innerHTML = 'anything';
document.querySelector('body').appendChild(newEl);
而不是设置
body.innerHTML
属性


仅供参考,您可能应该将
警报
切换到
控制台。日志
s,因为警报会让人恼火,而控制台是在开发过程中进行测试的方式。

您遇到了一个问题,浏览器已刷新文档并转储其保存的属性。也称为。访问某些DOM属性(和/或调用某些DOM方法)“将触发浏览器同步计算样式和布局”。这句话出自保罗·爱尔兰的名言。虽然
innerHTML
没有包含在其中,但可以肯定这是罪魁祸首

在您的示例中,第一个警报之所以有效,原因很明显。第二种方法有效,因为您要求浏览器查找元素并再次获取属性。第三个失败是因为您依赖于存储的值(不再存储)

最简单的解决方法是在使用强制回流的方法/属性时使用
requestAnimationFrame

window.addEventListener('load',pageInit);
函数pageInit(){
//保存实例以供以后使用
var元素=document.querySelector(“#元素”);
console.log(“before:”,element.clientHeight);//返回40
requestAnimationFrame(函数(){
document.querySelector('body').innerHTML+=';
});
console.log(“后面是rAF:”,element.clientHeight);//返回~0~40!
//又到野外去了
document.querySelector('body').innerHTML+=';
//哦,不!
console.warn(“W/O rAF after:”,element.clientHeight);//返回0
}
#元素{
高度:40px;
}

注意返回一个元素;返回一个非活动的
节点列表
。感谢您指出这一点,我将编辑这个问题。发布的代码片段可能的重复只是一个较大网站的调试重构,在这个网站中,我更喜欢在正文的末尾直接插入原始svg符号定义,或者:
document.querySelector('body')。insertAdjacentHTML(“beforeed”“任何事”

或任何其他非破坏性插入方法。-无论如何,是的,换句话说,最重要的部分是理解
.innerHTML+=
将1:获取元素的innerHTML的字符串表示,2。在其上附加另一个字符串,然后单击3。将该复合字符串返回到元素的内部“body”中,这样(正如正确指出的)将使以前的任何引用都无用。明白了。我以为你想给身体添加元素,我的bad@RokoC.Buljan有趣的是,当我测试将新元素添加到主体时,对
div#element
的旧引用现在自动指向新元素。我假设chrome足够聪明,可以意识到旧的div已经存在,它不需要重新创建。我觉得这很酷,可以分享:)chrome版本56.0.2924.87仍然复制同样的行为,我想从现在起我会坚持使用非破坏性插入