gpt4 book ai didi

javascript - `$().clone(true)` 破坏 Chrome 扩展中的事件处理程序(适用于 jsbin)

转载 作者:行者123 更新时间:2023-12-02 13:48:06 28 4
gpt4 key购买 nike

我正在开发一个 Chrome 扩展,它可能会改变数千个 DOM 元素。出于性能原因,我想在内存中执行此操作,而不是重复触摸 DOM。 jQuery's clone正如您在下面的代码片段中看到的那样,对此非常有效。

$(document).ready(function() {
$("#click-me").on("click", () => {
$("#click-count").html((idx, num) => ++num)
})

$("#with-cloning").click(function() {
withCloning(($elem) => {
$elem.find("h1").text("changed with cloning (still works)")
})
})

$("#without-cloning").click(function() {
withoutCloning(($elem) => {
$elem.find("h1").text("changed without cloning (still works)")
})
})
})

function withCloning(mutateDom) {
var $elem = $("body")
// The `true` arg keeps bindings
var $cloned = $elem.clone(true)
mutateDom($cloned)
$elem.replaceWith($cloned)
}

function withoutCloning(mutateDom) {
mutateDom($("body"))
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="wrapper">
<h1 id="click-me">Click me!</h1>
<p>Click count: <span id="click-count">0</span></p>
</div>

<button id="without-cloning">replace without cloning</button>
<button id="with-cloning">replace with cloning</button>


<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

</body>
</html>

当我在 Chrome 扩展中使用这个完全相同的函数时,它成功替换了内容,但破坏了所有事件处理程序

以下函数在嵌入网站(和代码片段)我的 Chrome 扩展程序中时都可以完美运行:

function withoutCloning(mutateDom) {
mutateDom($("body"))
}

如何使 withCloning 函数在 Chrome 扩展程序中正确运行(如代码片段中所示)?

<小时/>

附加说明

  • jQuery clone docs如此描述 clone 的可选参数:

    A Boolean indicating whether event handlers should be copied along with the elements. As of jQuery 1.4, element data will be copied as well.

  • 如果有其他更合适的东西(也许是文档片段),我不会以任何方式依赖于使用 jQuery 的克隆

  • 我通过传入 $elem => $elem 验证了冲突与 mutateDom 函数无关。问题依然存在。

最佳答案

您正在做的事情预计会破坏事件处理程序。您无法克隆事件处理程序,除了通过 jQuery 方法添加的事件之外,还可以使用 jQuery 方法进行克隆或替换。因此,用克隆副本替换 DOM 的内容将导致删除事件处理程序。

jQuery .clone()无法克隆非 jQuery 事件

当事件监听器不是通过 jQuery 方法添加时,jQuery 无法知道元素上发生了什么事件。因此,通过普通 DOM 方法(即 .addEventListener() )添加的任何事件都不会被 jQuery 的 .clone() 克隆。 .

这是一个使用 addEventListener() 添加计数事件处理程序的示例。你可以看到 jQuery .clone()不克隆它,但克隆 jQuery 事件(也 available on JS Bin ):

$(document).ready(function() {
document.querySelector("#click-me").addEventListener("click", () => {
$("#click-count").html((idx, num) => ++num)
})

$("#with-cloning").click(function() {
withCloning(($elem) => {
$elem.find("h1").text("changed with cloning (counting does not work)")
})
})

$("#without-cloning").click(function() {
withoutCloning(($elem) => {
$elem.find("h1").text("changed without cloning (still works)")
})
})
})

function withCloning(mutateDom) {
var $elem = $("body")
// The `true` arg keeps bindings
var $cloned = $elem.clone(true)
mutateDom($cloned)
$elem.replaceWith($cloned)
}

function withoutCloning(mutateDom) {
mutateDom($("body"))
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="wrapper">
<h1 id="click-me">Click me!</h1>
<p>Click count: <span id="click-count">0</span></p>
</div>

<button id="without-cloning">replace without cloning</button>
<button id="with-cloning">replace with cloning</button>


<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

</body>
</html>

jQuery 可以克隆 jQuery 方法添加的事件

这在您的 JS Bin 中起作用的原因是您使用 jQuery 添加了所有事件处理程序。 jQuery 实际上保留了您通过 jQuery 添加的事件处理程序的记录,并且能够在您.clone() 时克隆 jQuery 添加的事件以及元素。元素,或使用 .replaceWith()来替换该元素。 jQuery 事件处理程序的恢复发生在两者 .clone() .replaceWith() 。换句话说,即使使用正常的 JavaScript 方法( node.cloneNode() Node.replaceChild() )执行这两个操作之一,而使用 jQuery 的方法( .clone().replaceWith() )执行另一个操作,jQuery 也会恢复您所发生的事件。使用 jQuery 添加。您可以使用以下代码片段来尝试使用 jQuery 与普通 JavaScript 的组合进行克隆并替换元素 ( also on JS Bin ):

$(document).ready(function() {
$("#click-me").on("click", () => {
$("#click-count").html((idx, num) => ++num);
});

$("#with-cloning").click(function() {
withCloning(($elem) => {
$elem.find("h1").text("changed with cloning (still works)");
});
});

$("#without-cloning").click(function() {
withoutCloning(($elem) => {
$elem.find("h1").text("changed without cloning (still works)");
});
});
});

function withCloning(mutateDom) {
var $elem = $("body")
var used='Used:';
var $cloned;
if($('#useClone').is(':checked')){
//jQuery clone. The `true` arg keeps bindings
$cloned = $elem.clone(true);
used += ' clone()';
} else {
//Vanilla JavaScript cloneNode. `true` makes a deep copy
$cloned = $($elem[0].cloneNode(true));
used += ' cloneNode()';
}
mutateDom($cloned);
if($('#useReplaceWith').is(':checked')){
//jQuery replaceWith
$elem.replaceWith($cloned);
used += ' and replaceWith()';
} else {
//Vanilla JavaScript replaceChild
$elem[0].parentNode.replaceChild($cloned[0],$elem[0]);
used += ' and replaceChild()';
}
console.log(used);
}

function withoutCloning(mutateDom) {
mutateDom($("body"));
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="wrapper">
<h1 id="click-me">Click me!</h1>
<p>Click count: <span id="click-count">0</span></p>
</div>

<button id="without-cloning">replace without cloning</button>
<button id="with-cloning">replace with cloning</button></br></br>
Use:</br>
<table>
<tr><td>jQuery</td><td>vanilla JavaScript</td></tr>
<tr>
<td><input name="cloneType" type="radio" id="useClone" checked="true">`.clone(true)`</input></td>
<td><input name="cloneType" type="radio" id="useCloneNode">`.cloneNode(true)`</input></td>
</tr>
<tr>
<td><input name="replaceType" type="radio" id="useReplaceWith" checked="true">`.replaceWith()`</input></td>
<td><input name="replaceType" type="radio" id="usereplaceChild">`.replaceChild()`</input></td>
</tr>
</table>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

</body>
</html>

请注意,一旦您使用 .cloneNode() 进行克隆, ,如果您尝试使用 .clone(true) 再次克隆,事件不会被克隆。

关于javascript - `$().clone(true)` 破坏 Chrome 扩展中的事件处理程序(适用于 jsbin),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41198843/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com