zone.js 和非 angular dom 元素事件的问题
Issue with zone.js and non angular dom element events
我遇到了 Zone.js 和非 angular DOM 元素事件的问题。
当我们将 javascript 函数分配给 HTML 标记中的任何 DOM 元素,然后以编程方式将相同的 DOM 元素重新分配给其他元素时,就会发生这种情况或相同的功能。
例如你有这个标记
<button id="button1" onclick="test1()">button 1</button>
然后在 JS 的某处你重新分配 button1 onclick 与一些其他功能
document.getElementById('button1').onclick = test3;
在这种情况下,会进行两次函数调用。第一个是原始分配的方法,然后第二个是新分配的方法。
我创建了一个 PLUNKER 来演示此行为。
在示例中,我们在屏幕上有一个 angular 应用程序和 2 个非 angular 按钮。每个按钮最初都分配了一个功能,该功能仅将一些文本打印到控制台。
一个按钮(onclick 事件上的按钮 1)仅打印 调用的测试 1 方法。
另一个按钮(onclick 事件上的按钮 2)打印 调用的测试 2 方法。 并且还为按钮 1 的 onclick 分配一个新函数。这个新函数打印 test 3 method called.
场景-
让应用程序加载。当您看到 App works 时,请执行以下操作:-
1. 打开调试器控制台。
2.点击按钮2
3.查看控制台
4. 点击按钮 1.
5. 检查控制台。
期待。
• 单击 Button 2 时,我们应该看到调用了 test 2 方法。
• 单击 Button 1 时,我们应该看到调用了 test 3 方法。
实际
• 单击按钮 2,我们看到调用了 test 2 方法。
• 单击按钮 1 时,我们看到调用了 test 1 方法。 随后是 test 3
调用的方法。
笨蛋 link
https://plnkr.co/edit/ymKcHjWPrDiG73NfWBle?p=preview
在调试时,我看到一个方法被称为 DOM 元素事件(来自 onclick 的 test1),另一个方法(test3)被 zonejs
调用
(对于这个调试,我在本地机器的 zone.js 文件中添加了 console.log)
我看到 zonejs 注册了与屏幕上任何 DOM 元素相关的几乎所有事件。
那么,这是我面临的问题吗?或者这是预期的行为还是我哪里出错了?请帮忙提供一些信息/指点。
不是 angular 但 zonejs 导致了此行为。处理一些试错。
https://plnkr.co/edit/cnDy4utsWYbhaXIBluNw?p=preview
- 将内联事件侦听器移动到
window.onload
- 更新了
test2()
方法以删除和添加按钮 1 的侦听器
问题是区域补丁 onclick
并使用 addEventListener/removeEventListener
到 register/remove 按钮的回调。但是 onclick
注册了它自己的独立处理程序,不能用 removeEventListener
删除。所以实际上你最终得到了 click
事件的两个处理程序:
function patchProperty(obj, prop, prototype) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
...
desc.set = function (newValue) {
...
var previousValue = target[_prop];
if (previousValue) {
// !!!!!! ------------------ it doesn't remove onclick here ---------- !!!!!!
target.removeEventListener(eventName, previousValue);
}
if (typeof newValue === 'function') {
var wrapFn = function (event) {
console.log(' zone wrap function called for--\n');
console.log('targetID '+target.id);
console.log('event is '+eventName);
var result = newValue.apply(this, arguments);
if (result != undefined && !result) {
event.preventDefault();
}
return result;
};
target[_prop] = wrapFn;
// !!!!!! ------------------ but adds new handler here ---------- !!!!!!
target.addEventListener(eventName, wrapFn, false);
这种情况很容易在没有区域的情况下重现:
function onClickHandler() {
console.log('onClickHandler');
}
document.addEventListener("DOMContentLoaded", function() {
const button = document.querySelector('button');
button.removeEventListener('click', button.onclick);
button.addEventListener('click', ()=> {
console.log('addEventListener')
});
});
<button onclick="onClickHandler()">Hello</button>
解决方法之一是修补 zone.js 的 "desc.set" 方法来解决此问题。
function patchProperty(obj, prop, prototype) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
...
desc.set = function (newValue) {
...
var previousValue = target[_prop];
if (previousValue) {
target.removeEventListener(eventName, previousValue);
}//Start Fix
else{
if(originalDescGet){
if (typeof target['removeAttribute'] === 'function') {
target.removeAttribute(prop);
}
}
}//End fix
我遇到了 Zone.js 和非 angular DOM 元素事件的问题。
当我们将 javascript 函数分配给 HTML 标记中的任何 DOM 元素,然后以编程方式将相同的 DOM 元素重新分配给其他元素时,就会发生这种情况或相同的功能。
例如你有这个标记
<button id="button1" onclick="test1()">button 1</button>
然后在 JS 的某处你重新分配 button1 onclick 与一些其他功能
document.getElementById('button1').onclick = test3;
在这种情况下,会进行两次函数调用。第一个是原始分配的方法,然后第二个是新分配的方法。
我创建了一个 PLUNKER 来演示此行为。
在示例中,我们在屏幕上有一个 angular 应用程序和 2 个非 angular 按钮。每个按钮最初都分配了一个功能,该功能仅将一些文本打印到控制台。
一个按钮(onclick 事件上的按钮 1)仅打印 调用的测试 1 方法。
另一个按钮(onclick 事件上的按钮 2)打印 调用的测试 2 方法。 并且还为按钮 1 的 onclick 分配一个新函数。这个新函数打印 test 3 method called.
场景-
让应用程序加载。当您看到 App works 时,请执行以下操作:-
1. 打开调试器控制台。
2.点击按钮2
3.查看控制台
4. 点击按钮 1.
5. 检查控制台。
期待。
• 单击 Button 2 时,我们应该看到调用了 test 2 方法。
• 单击 Button 1 时,我们应该看到调用了 test 3 方法。
实际
• 单击按钮 2,我们看到调用了 test 2 方法。
• 单击按钮 1 时,我们看到调用了 test 1 方法。 随后是 test 3
调用的方法。
笨蛋 link
https://plnkr.co/edit/ymKcHjWPrDiG73NfWBle?p=preview
在调试时,我看到一个方法被称为 DOM 元素事件(来自 onclick 的 test1),另一个方法(test3)被 zonejs
调用
(对于这个调试,我在本地机器的 zone.js 文件中添加了 console.log)
我看到 zonejs 注册了与屏幕上任何 DOM 元素相关的几乎所有事件。
那么,这是我面临的问题吗?或者这是预期的行为还是我哪里出错了?请帮忙提供一些信息/指点。
不是 angular 但 zonejs 导致了此行为。处理一些试错。
https://plnkr.co/edit/cnDy4utsWYbhaXIBluNw?p=preview
- 将内联事件侦听器移动到
window.onload
- 更新了
test2()
方法以删除和添加按钮 1 的侦听器
问题是区域补丁 onclick
并使用 addEventListener/removeEventListener
到 register/remove 按钮的回调。但是 onclick
注册了它自己的独立处理程序,不能用 removeEventListener
删除。所以实际上你最终得到了 click
事件的两个处理程序:
function patchProperty(obj, prop, prototype) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
...
desc.set = function (newValue) {
...
var previousValue = target[_prop];
if (previousValue) {
// !!!!!! ------------------ it doesn't remove onclick here ---------- !!!!!!
target.removeEventListener(eventName, previousValue);
}
if (typeof newValue === 'function') {
var wrapFn = function (event) {
console.log(' zone wrap function called for--\n');
console.log('targetID '+target.id);
console.log('event is '+eventName);
var result = newValue.apply(this, arguments);
if (result != undefined && !result) {
event.preventDefault();
}
return result;
};
target[_prop] = wrapFn;
// !!!!!! ------------------ but adds new handler here ---------- !!!!!!
target.addEventListener(eventName, wrapFn, false);
这种情况很容易在没有区域的情况下重现:
function onClickHandler() {
console.log('onClickHandler');
}
document.addEventListener("DOMContentLoaded", function() {
const button = document.querySelector('button');
button.removeEventListener('click', button.onclick);
button.addEventListener('click', ()=> {
console.log('addEventListener')
});
});
<button onclick="onClickHandler()">Hello</button>
解决方法之一是修补 zone.js 的 "desc.set" 方法来解决此问题。
function patchProperty(obj, prop, prototype) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
...
desc.set = function (newValue) {
...
var previousValue = target[_prop];
if (previousValue) {
target.removeEventListener(eventName, previousValue);
}//Start Fix
else{
if(originalDescGet){
if (typeof target['removeAttribute'] === 'function') {
target.removeAttribute(prop);
}
}
}//End fix