zone.js和非角度dom元素事件的问题

时间:2017-07-19 13:17:10

标签: angular dom zone.js

我遇到了Zone.js和非角度DOM元素事件的问题。

当我们将javascript函数分配给HTML标记中的任何DOM元素,然后以编程方式将相同的DOM元素重新分配给其他或相同的函数时,就会发生这种情况。

e.g。你有这个标记

<button id="button1" onclick="test1()">button 1</button>

然后在JS的某处你用其他函数重新分配button1 onclick

 document.getElementById('button1').onclick = test3;

在这种情况下,会进行两次函数调用。第一个是原始分配的方法,然后第二个是新分配的方法。

我创建了一个PLUNKER来演示这种行为。

在示例中,我们在屏幕上有一个角度应用程序和2个非角度按钮。每个按钮最初分配一个功能,只是将一些文本打印到控制台。

一个按钮(onclick事件上的按钮1)只打印测试1方法。

另一个按钮(onclick事件上的按钮2)打印测试2方法。并且还为button1分配一个新功能。这个新函数打印测试3方法,名为。

情景 -

让应用程序加载。当您看到应用程序作品时,请执行以下操作: -
1.打开调试器控制台 2.单击按钮2
3.检查控制台
4.单击按钮1.
5.检查控制台。

期望。
•点击按钮2,我们应该看到测试2方法。
•单击按钮1,我们应该看到测试3方法。

实际的 •单击按钮2,我们会看到测试2方法。
•点击按钮1,我们看到测试1方法被调用。后跟测试3
 方法叫做。

PLUNKER链接

https://plnkr.co/edit/ymKcHjWPrDiG73NfWBle?p=preview

在调试时,我看到一个方法称为DOM元素事件(来自onclick的test1),另一个方法(test3)由zonejs调用
(对于这个调试,我在本地机器上的zone.js文件中添加了console.log)

我看到zonejs注册了与屏幕上任何DOM元素相关的所有事件。

那么,这是我面临的问题吗?或者是预期的行为还是我在某个地方出错了?请帮忙解决一些信息/指示。

3 个答案:

答案 0 :(得分:1)

没有角度但是zonejs导致了这种行为。使用一些试验错误。

https://plnkr.co/edit/cnDy4utsWYbhaXIBluNw?p=preview

  1. 将内联事件侦听器移至window.onload
  2. 更新test2()方法以删除并添加button1
  3. 的侦听器

答案 1 :(得分:1)

问题是区域补丁onclick并使用addEventListener/removeEventListener注册/删除按钮的回调。但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>

答案 2 :(得分:1)

其中一个决议是修补&#34; desc.set&#34; zone.js的方法来解决这个问题。

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