我有一个巨大的jQuery应用程序,我正在使用下面的两个方法来处理点击事件。

第一个方法

HTML

<div id="myDiv">Some Content</div>

jQuery

$('#myDiv').click(function(){
    //Some code
});

第二种方法

HTML

<div id="myDiv" onClick="divFunction()">Some Content</div>

JavaScript函数调用

function divFunction(){
    //Some code
}

在我的应用程序中,我使用第一种或第二种方法。哪个更好?性能更好?和标准?


当前回答

性能

这里已经有很多很好的答案,然而,作者有时会提到性能,但实际上还没有人调查它-所以我将在这里集中讨论这方面。今天,我在Chrome 83.0, Safari 13.1和Firefox 77.0上进行测试,以解决上述问题和其他一些替代解决方案(其中一些在其他答案中提到)。

结果

我比较这里的A-H解因为它们作用于元素id。我还展示了使用类(I,J,K)作为参考的解的结果。

基于html内联处理程序绑定(B)的解决方案是快速和最快的Chrome和最快的少量元素 基于getElementById (C,D)的解决方案是快速的,对于大量的元素,在Safari和Firefox上最快 基于I,J的参考解决方案对于大数量的元素是最快的,所以在这种情况下值得考虑使用类代替id方法 基于jQuery的解决方案。点击(A)最慢

细节

实际上,针对这一问题设计性能测试并不容易。我注意到,对于所有测试的解决方案,10K div-s触发事件的性能都很快,手动我无法检测到它们之间的任何差异(你可以运行下面的代码片段自己检查)。因此,针对两种情况,我着重测量生成html和绑定事件处理程序的执行时间

10个div -你可以在这里运行测试 1000 div -你可以在这里运行测试

// https://stackoverflow.com/questions/12627443/jquery-click-vs-onclick let a= [...Array(10000)]; function clean() { test.innerHTML = ''; console.clear() } function divFunction(el) { console.log(`clicked on: ${el.id}`); } function initA() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> $(`#myDiv${i}`).click(e=> divFunction(e.target))); } function initB() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box" onclick="divFunction(this)">${i}</div>`).join``; } function initC() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.getElementById(`myDiv${i}`).onclick = e=> divFunction(e.target) ); } function initD() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.getElementById(`myDiv${i}`).addEventListener('click', e=> divFunction(e.target) )); } function initE() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.querySelector(`#myDiv${i}`).onclick = e=> divFunction(e.target) ); } function initF() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.querySelector(`#myDiv${i}`).addEventListener('click', e=> divFunction(e.target) )); } function initG() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> window[`myDiv${i}`].onclick = e=> divFunction(e.target) ); } function initH() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> window[`myDiv${i}`].addEventListener('click',e=> divFunction(e.target))); } function initI() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; [...document.querySelectorAll(`.box`)].map(el => el.onclick = e=> divFunction(e.target)); } function initJ() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; [...document.querySelectorAll(`.box`)].map(el => el.addEventListener('click', e=> divFunction(e.target))); } function initK() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; $(`.box`).click(e=> divFunction(e.target)); } function measure(f) { console.time("measure "+f.name); f(); console.timeEnd("measure "+f.name) } #test { display: flex; flex-wrap: wrap; } .box { margin: 1px; height: 10px; background: red; font-size: 10px; cursor: pointer; } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div>This snippet only presents used solutions. Click to solution button and then click on any red box to trigger its handler</div> <button onclick="measure(initA)">A</button> <button onclick="measure(initB)">B</button> <button onclick="measure(initC)">C</button> <button onclick="measure(initD)">D</button> <button onclick="measure(initE)">E</button> <button onclick="measure(initF)">F</button> <button onclick="measure(initG)">G</button> <button onclick="measure(initH)">H</button> <button onclick="measure(initI)">I</button> <button onclick="measure(initJ)">J</button> <button onclick="measure(initK)">K</button> <button onclick="clean()">Clean</button> <div id="test"></div>

下面是Chrome的测试示例

其他回答

性能

这里已经有很多很好的答案,然而,作者有时会提到性能,但实际上还没有人调查它-所以我将在这里集中讨论这方面。今天,我在Chrome 83.0, Safari 13.1和Firefox 77.0上进行测试,以解决上述问题和其他一些替代解决方案(其中一些在其他答案中提到)。

结果

我比较这里的A-H解因为它们作用于元素id。我还展示了使用类(I,J,K)作为参考的解的结果。

基于html内联处理程序绑定(B)的解决方案是快速和最快的Chrome和最快的少量元素 基于getElementById (C,D)的解决方案是快速的,对于大量的元素,在Safari和Firefox上最快 基于I,J的参考解决方案对于大数量的元素是最快的,所以在这种情况下值得考虑使用类代替id方法 基于jQuery的解决方案。点击(A)最慢

细节

实际上,针对这一问题设计性能测试并不容易。我注意到,对于所有测试的解决方案,10K div-s触发事件的性能都很快,手动我无法检测到它们之间的任何差异(你可以运行下面的代码片段自己检查)。因此,针对两种情况,我着重测量生成html和绑定事件处理程序的执行时间

10个div -你可以在这里运行测试 1000 div -你可以在这里运行测试

// https://stackoverflow.com/questions/12627443/jquery-click-vs-onclick let a= [...Array(10000)]; function clean() { test.innerHTML = ''; console.clear() } function divFunction(el) { console.log(`clicked on: ${el.id}`); } function initA() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> $(`#myDiv${i}`).click(e=> divFunction(e.target))); } function initB() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box" onclick="divFunction(this)">${i}</div>`).join``; } function initC() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.getElementById(`myDiv${i}`).onclick = e=> divFunction(e.target) ); } function initD() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.getElementById(`myDiv${i}`).addEventListener('click', e=> divFunction(e.target) )); } function initE() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.querySelector(`#myDiv${i}`).onclick = e=> divFunction(e.target) ); } function initF() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> document.querySelector(`#myDiv${i}`).addEventListener('click', e=> divFunction(e.target) )); } function initG() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> window[`myDiv${i}`].onclick = e=> divFunction(e.target) ); } function initH() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; a.map((x,i)=> window[`myDiv${i}`].addEventListener('click',e=> divFunction(e.target))); } function initI() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; [...document.querySelectorAll(`.box`)].map(el => el.onclick = e=> divFunction(e.target)); } function initJ() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; [...document.querySelectorAll(`.box`)].map(el => el.addEventListener('click', e=> divFunction(e.target))); } function initK() { test.innerHTML = a.map((x,i)=> `<div id="myDiv${i}" class="box">${i}</div>`).join``; $(`.box`).click(e=> divFunction(e.target)); } function measure(f) { console.time("measure "+f.name); f(); console.timeEnd("measure "+f.name) } #test { display: flex; flex-wrap: wrap; } .box { margin: 1px; height: 10px; background: red; font-size: 10px; cursor: pointer; } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div>This snippet only presents used solutions. Click to solution button and then click on any red box to trigger its handler</div> <button onclick="measure(initA)">A</button> <button onclick="measure(initB)">B</button> <button onclick="measure(initC)">C</button> <button onclick="measure(initD)">D</button> <button onclick="measure(initE)">E</button> <button onclick="measure(initF)">F</button> <button onclick="measure(initG)">G</button> <button onclick="measure(initH)">H</button> <button onclick="measure(initI)">I</button> <button onclick="measure(initJ)">J</button> <button onclick="measure(initK)">K</button> <button onclick="clean()">Clean</button> <div id="test"></div>

下面是Chrome的测试示例

关注点分离是这里的关键,因此事件绑定是普遍接受的方法。这基本上是很多现有答案的答案。

但是,不要过快地抛弃声明性标记的想法。它有它的位置,和像Angularjs这样的框架一起,它是核心。

需要有一个理解,整个<div id="myDiv" onClick="divFunction()>Some Content</div>被严重羞辱,因为它被一些开发人员滥用。所以它达到了亵渎的比例,就像桌子一样。有些开发人员实际上避免使用表格来处理表格数据。这是人们不理解行为的完美例子。

尽管我喜欢把我的行为和我的观点分开。我认为标记声明它做什么(而不是它如何做,这是行为)没有问题。它可能是一个实际的onClick属性的形式,也可能是一个自定义属性的形式,很像bootstrap javascript组件。

这样,只需看一眼标记,就可以看到它做了什么,而不是试图反向查找javascript事件绑定器。

因此,作为上述方法的第三种替代方法,使用数据属性来声明标记中的行为。行为被排除在视图之外,但一眼就能看到发生了什么。

自举的例子:

<button type="button" class="btn btn-lg btn-danger" data-toggle="popover" title="Popover title" data-content="And here's some amazing content. It's very engaging. Right?">Click to toggle popover</button>

来源:http://getbootstrap.com/javascript/弹窗

注意:第二个示例的主要缺点是对全局名称空间的污染。这可以通过使用上面的第三种选择来避免,或者使用像Angular这样的框架及其带有自动作用域的ng-click属性。

使用$('#myDiv').click(function(){更好,因为它遵循标准的事件注册模型。(jQuery内部使用addEventListener和attachEvent)。

基本上,以现代方式注册事件是处理事件的一种不引人注目的方式。另外,要为目标注册多个事件监听器,可以为同一个目标调用addEventListener()。

var myEl = document.getElementById('myelement');

myEl.addEventListener('click', function() {
    alert('Hello world');
}, false);

myEl.addEventListener('click', function() {
    alert('Hello world again!!!');
}, false);

http://jsfiddle.net/aj55x/1/

Why use addEventListener? (From MDN) addEventListener is the way to register an event listener as specified in W3C DOM. Its benefits are as follows: It allows adding more than a single handler for an event. This is particularly useful for DHTML libraries or Mozilla extensions that need to work well even if other libraries/extensions are used. It gives you finer-grained control of the phase when the listener gets activated (capturing vs. bubbling) It works on any DOM element, not just HTML elements.

更多关于现代活动注册-> http://www.quirksmode.org/js/events_advanced.html

其他方法,如设置HTML属性,示例:

<button onclick="alert('Hello world!')">

或DOM元素属性,示例:

myEl.onclick = function(event){alert('Hello world');}; 

都是旧的,而且很容易被重写。

应该避免使用HTML属性,因为它会使标记更大,可读性更差。内容/结构和行为的关注点没有很好地分开,使得错误更难被发现。

DOM元素属性方法的问题在于,每个事件只能将一个事件处理程序绑定到一个元素。

更多关于传统事件处理-> http://www.quirksmode.org/js/events_tradmod.html

MDN参考:https://developer.mozilla.org/en-US/docs/DOM/event

这样做,因为它将为您提供标准和性能。

 $('#myDiv').click(function(){
      //Some code
 });

因为第二种方法是简单的JavaScript代码,比jQuery更快。但这里的性能大致相同。

说你有一个按钮嵌套在Javascript/Jquery生成的html元素(.html()或.innerHTML类型的元素),然后你需要首先选择最外层的元素(父元素),并这样做

var parentElement = $('#outermostElement')
 parentElement.click('button', function(){
    console.log('clicked')
}) 

我所说的最外层元素是指嵌入.html()的元素

outermostElement.html("<div><button>click<button><div>")