使用原生 Javascript 实现 jQuery 的“实时”活页夹

IT技术 javascript jquery event-handling dom-events
2021-03-15 03:54:25

我想弄清楚如何将事件绑定到动态创建的元素。即使在元素被销毁和重新生成后,我也需要该事件在元素上持续存在。

显然,使用 jQuery 的 live 函数很容易,但是使用原生 Javascript 实现它们会是什么样子?

4个回答

这是一个简单的例子:

function live(eventType, elementId, cb) {
    document.addEventListener(eventType, function (event) {
        if (event.target.id === elementId) {
            cb.call(event.target, event);
        }
    });
}

live("click", "test", function (event) {
    alert(this.id);
});

基本思想是您希望将事件处理程序附加到文档并让事件在 DOM 中冒泡。然后,检查event.target属性以查看它是否符合所需的条件(在这种情况下,只是id元素的 )。

编辑:

@shabunc在我的解决方案中发现了一个相当大的问题——无法正确检测到子元素上的事件。解决此问题的一种方法是查看祖先元素以查看是否有指定的id

function live (eventType, elementId, cb) {
    document.addEventListener(eventType, function (event) {
        var el = event.target
            , found;

        while (el && !(found = el.id === elementId)) {
            el = el.parentElement;
        }

        if (found) {
            cb.call(el, event);
        }
    });
}
到文档或更有效地 - 到您不期望您感兴趣的元素之外的容器。
2021-04-20 03:54:25
所以这只是监听任何点击事件,当点击事件发生时,它会检查目标的 id 是否与给定的 id 匹配并执行回调函数。非常有趣 :)
2021-04-22 03:54:25
对。正如@Tadeck 指出的那样,您可以将冒泡限制为另一个包含元素,以获得更高效的侦听器。
2021-05-03 03:54:25
@Binyamin:您必须编写一些解析该选择器的内容。如果您正在处理复杂的选择器,最好使用 jQuery 或其他框架。
2021-05-15 03:54:25
这不适用于子 DOM 元素,尽管我们实际上也认为这是一个有效的点击事件。
2021-05-17 03:54:25

除了 Andrew 的帖子和 Binyamin 的评论之外,也许这是一个选项:

有了这个,您可以使用“nav .item a”作为选择器。基于安德鲁的代码。

function live (eventType, elementQuerySelector, cb) {
    document.addEventListener(eventType, function (event) {

        var qs = document.querySelectorAll(elementQuerySelector);

        if (qs) {
            var el = event.target, index = -1;
            while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
                el = el.parentElement;
            }

            if (index > -1) {
                cb.call(el, event);
            }
        }
    });
}



live('click', 'nav .aap a', function(event) { console.log(event); alert('clicked'); });
非常感谢。我建议的一件事是支持e.preventDefault()inside addEventListener如果使用,那么您需要将其更改为document.querySelector(elementQuerySelector).addEventListener(eventType, function (event) {else 它将阻止您单击页面上的任何其他元素
2021-05-12 03:54:25

其他解决方案有点过于复杂......

document.addEventListener('click', e => {
   if (e.target.closest('.element')) {
       // .element has been clicked
   }
}

如果您需要支持 Internet Explorer 或旧浏览器,可以使用polyfill

好问题。我想我会发现哈哈..到处都用这个
2021-04-20 03:54:25
这是纯金……尤其是在事后添加 html 时使用 ajax 函数。这是完美的。谢谢 !
2021-04-22 03:54:25
@Oneezy 谢谢!对于该用例,您可以编写document.querySelector('.ajax-container')而不是document提高性能。
2021-04-25 03:54:25
@Oneezy 不错,是的,如果您使用 JavaScript 创建元素,最好直接添加侦听器。但是,如果您从服务器获取原始 HTML,实时绑定可以为您节省大量精力:) 我想知道需要多长时间才能产生明显的性能影响,我在测试中从未遇到任何问题(使用单击侦听器)。
2021-05-05 03:54:25
不错的主意!疯狂的是,这段代码允许我停止for (const element of elements) { ... }在需要使用 ajax 的点击事件的地方使用我的东西。我很想知道性能缺点是什么......似乎可能有一些。我和我的朋友 Joah 交谈过,他重新编写了代码以提高性能。w/他的版本,点击事件发生在实际<button>本身,而不是文档上。查看codepen.io/oneezy/pen/QWGyXzd
2021-05-12 03:54:25

将事件动态绑定到特定元素的替代方法可能是全局事件侦听器。因此,每次使用该元素上的另一个新元素事件更新 DOM 时,也会“捕获”。一个例子:

var mybuttonlist = document.getElementById('mybuttonlist');

mybuttonlist.addEventListener('click', e=>{
  if(e.target.nodeName == 'BUTTON'){
    switch(e.target.name){
      case 'createnewbutton':
        mybuttonlist.innerHTML += '<li><button name="createnewbutton">Create new button</button></li>';
        break;
    }
  }
}, false);
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}
<ul id="mybuttonlist">
  <li><button name="createnewbutton">Create new button</button></li>
</ul>

在这个例子中,我有一个<ul>关于点击事件的事件监听器因此,所有子元素都会发生一个事件。从我创建的简单事件处理程序中,您可以看到添加更多逻辑、更多按钮(具有不同或重复名称)、锚点等很容易。

总而言之,您可以将事件侦听器添加到文档而不是列表元素,捕获页面上的所有点击事件,然后在事件处理程序中处理点击事件。

这是一个很酷的主意!但我宁愿使用data-event它没有语义意义。并添加一些方法来更改事件选项。对于我推荐的这样的代码Vue.js,为您处理所有这些事情;)
2021-04-23 03:54:25
@FabianvonEllerts 谢谢,但我不认为这是一个很酷的主意——这就是普通 JavaScript 和 DOM 的工作原理。在我的示例中,您可以让事件侦听器侦听整个文档,然后使用“data-”属性来选择正确的操作 - 这只是示例的一小部分重写:jsbin.com/dabetonasi/edit?html,js ,输出
2021-05-13 03:54:25