更改事件的currentTarget以进行事件委托

时间:2020-03-04 17:17:10

标签: javascript dom-events

我正在尝试在网站上添加一些委托事件,但我没有一个与传统侦听器回调签名(function( event ) {})匹配的函数,并且要获取当前的侦听元素,我需要将另一个参数传递给函数

这是我设法实现的目标:

const delegate = function( element, events, target, callback ) {
    events.split( " " ).forEach( event => element.addEventListener( event, function( e ) {
        let initiator;
        if ( e.target && ( initiator = e.target.closest( target ) ) ) {
            callback( e, initiator );
        }
    } ) );
};

let count = 0;

delegate( document, "click", ".js-test-delegate", function( event, elem ) {
  elem.innerHTML = `you click on this container ${++count} time(s)`;
} );


const div = document.createElement("div")
div.classList.add( "js-test-delegate" );

document.querySelector( ".container" ) .appendChild( div );
.container{
  width: 300px;
  height: 300px;
  background: rgba(256,0,0,.2);
}

.js-test-delegate{
  width: 100px;
  height: 100px;
  position: relative;
  top: 100px;
  left: 100px;
  background: rgba(0,256,0,.2);
}
<div class="container"></div>

是否可以通过方法在事件中传递elem元素,以使他替换currentTarget属性以使其行为更简单?

我尝试修改Event,但是currentTarget之类的属性是只读的,或者克隆事件event = new Event( "click", e)targetcurrentTarget暂时未设置。 / p>

当然,这需要在普通js中使用。

谢谢!

2 个答案:

答案 0 :(得分:0)

使用.call()调用以元素引用作为this值的回调:

    if ( e.target && ( initiator = e.target.closest( target ) ) ) {
        callback.call(initiator, e);
    }

在回调中,this将引用“启动器”,并且您不需要其他参数。

答案 1 :(得分:0)

您可以将所需元素作为自定义属性添加到事件对象,如下所示:

const delegate = function( element, events, target, callback ) {
    events.split(" ").forEach(event => element.addEventListener(event, function(e) {
       let initiator = e.target.closest(target);
       if (e.target && initiator) {
           e.initiator= initiator;
           callback(e);
           // If you want also to bind this to the initiator, call:
           // callback.call(initiator, e);
       }
    }));
};

现在,您可以从event对象中读取自定义属性:

delegate(document, 'click', '.js-test-delegate'", function(e) {
  e.initiator.innerHTML = `you click on this container ${++count} time(s)`;
});

可以绕过event对象中的属性的只读保护,但不是一件容易的事。您将需要创建一个新对象,并向其中添加所有属性,并将所有方法的this值绑定到原始事件。这是fiddle进行的操作,但是尚未经过充分测试,并且可能会因某些特定事件而失败。