如何防止 Google Polymer 改变 event.target?

How to prevent Google Polymer from changing event.target?

我一直在研究 Google Polymer Shop demo 并注意到聚合物系统地将 DOM 事件目标更改为顶级组件(在本例中为 <shop-app>)。

  1. 转到https://shop.polymer-project.org/
  2. 打开控制台
  3. 粘贴下面的事件侦听器

document.addEventListener('click', function(event){ console.log('DOM click event target:',event.target); });

  1. 单击演示并查看控制台日志

如您所见,聚合物系统地 returns <shop-app> 作为 event.target 即使您单击不同的元素:

此行为的问题在于它破坏了所有使用事件侦听器 来检索有关原始事件目标的信息的外部 JavaScript 库(它们只看到 <shop-app>一直)。

作为一种解决方法,我一直在尝试检索原始事件目标 (Polymer.dom(event).path[0]) 并使用它发送一个新事件 (https://pastebin.com/WKhGMrfx),但由于某种原因,我的新事件没有'dispatch(我知道我最终会得到重复的事件,但我的外部库会工作,因为至少其中一些事件会有适当的 - 原始 - 事件目标):

还有我的问题:

Q1:有没有办法防止聚合物覆盖event.target

Q2:有没有办法用原来的事件目标派发事件?

运行 此代码来自聚合物商店演示页面的控制台,然后检查点击事件的目标

function addEventListenerOverride(obj) {
    if(obj._addEventListener)
        return
    obj._addEventListener = obj.addEventListener;
    obj.addEventListener = function(a,b,c) {
        if(c==undefined)
            c=false;
        this._addEventListener(a,b,c);
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(!this.eventListenerList[a])
            this.eventListenerList[a] = [];
        //this.removeEventListener(a,b,c); // TODO - handle duplicates..
        this.eventListenerList[a].push({listener:b,useCapture:c});
    };

    obj.getEventListeners = function(a){
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(a==undefined)
            return this.eventListenerList;
        return this.eventListenerList[a];
    };
    obj.clearEventListeners = function(a){
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(a==undefined){
            for(var x in (this.getEventListeners())) this.clearEventListeners(x);
                return;
        }
        var el = this.getEventListeners(a);
        if(el==undefined)
            return;
        for(var i = el.length - 1; i >= 0; --i) {
            var ev = el[i];
            this.removeEventListener(a, ev.listener, ev.useCapture);
        }
    };

    obj._removeEventListener = obj.removeEventListener;
    obj.removeEventListener = function(a,b,c) {
        if(c==undefined)
            c=false;
        this._removeEventListener(a,b,c);
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(!this.eventListenerList[a])
            this.eventListenerList[a] = [];

    // Find the event in the list
    for(var i=0;i<this.eventListenerList[a].length;i++){
    if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm..
        this.eventListenerList[a].splice(i, 1);
        break;
    }
    }
    if(this.eventListenerList[a].length==0)
        delete this.eventListenerList[a];
    };
}

addEventListenerOverride(Element.prototype);
addEventListenerOverride(document);
addEventListenerOverride(document.body);



document.addEventListener('click', function(event){
    if(event.isCustomized)
        return
    event.stopPropagation();
    event.preventDefault();
    event.stopImmediatePropagation();
    //console.log('DOM click event 1:',event,'target:',event.target);
    var normalizedEvent = Polymer.dom(event);



    //event.oldTarget = event.target;
    //event.target = normalizedEvent.rootTarget;


    // logs #myButton
    //console.info('rootTarget is:', normalizedEvent.rootTarget);
    // logs the instance of event-targeting that hosts #myButton
    //console.info('localTarget is:', normalizedEvent.localTarget);
    // logs [#myButton, document-fragment, event-retargeting,
    //       body, html, document, Window]
    //console.info('path is:', normalizedEvent.path);

    var config = {};
    for(var c in event){
        config[c] = event[c];
    }

    config.bubbles = false;

    var newTarget = normalizedEvent.rootTarget;
    var eventType = event.type;


    console.log("target should be: ", newTarget)

    //config.target = normalizedEvent.rootTarget;

    var fn = function(subEvent){
        subEvent.preventDefault();
        subEvent.stopImmediatePropagation();
        //console.log("subEvent", subEvent.target)
        //subEvent.type = "";
        //console.log("subEvent", subEvent.type)

        var listeners = document.getEventListeners(eventType);
        if(listeners && listeners.length){
            for(var i=0; i<listeners.length;i++){
                var l = listeners[i].listener;
                //l.call();
                l(subEvent)
            }
        }
        newTarget.removeEventListener(eventType, fn)
    }
    var oldEventListeners = (newTarget.getEventListeners(eventType) || []).concat([]);
    console.log("oldEventListeners1", oldEventListeners)
    newTarget.clearEventListeners(eventType);
    newTarget.addEventListener(eventType, fn);
    console.log("oldEventListeners2", oldEventListeners)
    oldEventListeners.forEach(function(a){
        newTarget.addEventListener(eventType, a.listener, a.useCapture);
    })



    var newEvent = new event.constructor(eventType, config);
    newEvent.isCustomized = true;

    //var shopAppEl = document.querySelector("shop-app");

    //shopAppEl.fire(event.type, event.details, {node: newTarget})
    setTimeout(function(){
        try{
            newTarget.dispatchEvent(newEvent);
        }catch(e){
            console.log("error", e)
        }
    },100)


});

document.addEventListener('click', function(event){
    console.log('DOM click event:', event, 'target:', event.target);
});

这段代码中的事件不是真实事件,而是一个克隆对象

function addEventListenerOverride(obj) {
    if(obj._addEventListener){
        obj.addEventListener = obj._addEventListener;
        obj.removeEventListener = obj._removeEventListener;
    }
    obj._addEventListener = obj.addEventListener;
    obj.addEventListener = function(a,b,c) {
        if(c==undefined)
            c=false;
        this._addEventListener(a,b,c);
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(!this.eventListenerList[a])
            this.eventListenerList[a] = [];
        //this.removeEventListener(a,b,c); // TODO - handle duplicates..
        this.eventListenerList[a].push({listener:b,useCapture:c});
    };

    obj.getEventListeners = function(a){
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(a==undefined)
            return this.eventListenerList;
        return this.eventListenerList[a];
    };
    obj.clearEventListeners = function(a){
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(a==undefined){
            for(var x in (this.getEventListeners()))
                this.clearEventListeners(x);
            return;
        }
        var el = this.getEventListeners(a);
        if(el==undefined)
            return;
        for(var i = el.length - 1; i >= 0; --i) {
            var ev = el[i];
            this.removeEventListener(a, ev.listener, ev.useCapture);
        }
    };

    obj._removeEventListener = obj.removeEventListener;
    obj.removeEventListener = function(a,b,c) {
        if(c==undefined)
            c=false;
        this._removeEventListener(a,b,c);
        if(!this.eventListenerList)
            this.eventListenerList = {};
        if(!this.eventListenerList[a])
            this.eventListenerList[a] = [];

    // Find the event in the list
    for(var i=0;i<this.eventListenerList[a].length;i++){
        if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm..
            this.eventListenerList[a].splice(i, 1);
            break;
        }
    }
    if(this.eventListenerList[a].length==0)
        delete this.eventListenerList[a];
    };
}

//addEventListenerOverride(Element.prototype);
addEventListenerOverride(document);
//addEventListenerOverride(document.body);



function onDocumentClick(event){
    if(event.isCustomized)
        return
    event.stopPropagation();
    //event.preventDefault();
    event.stopImmediatePropagation();
    var normalizedEvent = Polymer.dom(event);

    var eventClone = {};
    for(var c in event){
        eventClone[c] = event[c];
    }

    eventClone.target = normalizedEvent.rootTarget;
    eventClone.isCustomized = true;
    var eventType = event.type;

    console.log("target should be: ", eventClone.target)

    var listeners = document.getEventListeners(eventType);
    if(listeners && listeners.length){
        for(var i=0; i<listeners.length;i++){
            listeners[i].listener(eventClone)
        }
    }
}
document.addEventListener('click', onDocumentClick);

document.addEventListener('click', function(event){
    console.log('DOM click event:', event, 'target:', event.target);
});