<script> function print(){ console.log(1) } X.onclick = print; //是对的 Y.onclick = print(); Z.onclick = print.call(); </script> <button id='X' onclick='print'>A</button> <button id='Y' onclick='print()'>B</button> //是对的 <button id='Z' onclick='print.call()'>C</button> //是对的
HTML 中onclick = '要执行的代码'
,一旦用户点击,浏览就eval('要执行的代码'),这里不是属性,不是函数,是一段代码。
JavaScript 中,一旦用户点击,浏览器就执行X.onclick.call(X,{})
,意思是onclick
是一个函数属性,而print
是一个属性,由于它的类型是对象;但下面的print()
的类型是undefined
。
因此在HTML 中必须传递一个要执行的代码,JavaScript 中必须传递一个函数html
<button id='xxx'>A<button> xxx.addEventListener('click',function(){ console.log(1) }) xxx.onclick = function(){ console.log(2) }
那它们两个的区别是啥呢?xxx.onclick = function(){}
只是一个属性,因此它是惟一的,若是这时候你要绑定2个onclick
事件就麻烦了。xxx.addEventListener()
它是一个队列,先进先出,就是说先绑定的先触发。因此它叫作事件监听队列,这里是排队,xxx
拥有一个队列叫作eventlisteners
,你不能直接访问它,但你能够经过addEventListener
去排个队,若是用户点击了,就先触发排在第一位的函数,排在后面的一次触发。队列的实质是数组。既然有入队,那是否是也有出队:node
function f1(){ console.log(1); } function f2(){ console.log(2); } function f1(){ console.log(3); } xxx.addEventListener('click',f1); xxx.addEventListener('click',f2); xxx.removeEventListener('click',f1); xxx.addEventListener('click',f3); xxx.removeEventListener('click',f3);
最后的结果就是打印:2。
f1 在排队的过程当中移除了,f3 刚进入队列就移除了。数组
前面写轮播的时候用了one
事件,它内部是怎样的呢?浏览器
function f1(){ console.log(1); xxx.removeEventListener('click',f1); } xxx.addEventListener('click',f1);
one
在函数处理时的最后一句加上离开队列语句,on
就是没有出队这句的,也就是说一直会执行。函数
捕获事件:事件从最外层父元素到最里层子元素的顺序触发,叫作捕获事件,果document > html > body > div > p > button
代理
冒泡事件:正好和捕获事件相反,事件从最里层子元素到最外层父元素的顺序触发,叫作冒泡事件,如:button > p > div > body > html > document
code
DOM 2 中规定了同时支持捕获事件和冒泡事件,用addEventListener()
方法绑定一个事件处理函数,其语法:target.addEventListener(type, listener, useCapture);
type
:表示监听事件类型的字符串,如clcik
,前面没有on
listener
:表示监听的对象或者一个函数useCapture
:表示是否使用捕获,接受一个布尔值,true
是触发捕获事件,不写默认false
触发用冒泡事件。htm
事件在默认执行的过程当中是先捕获后冒泡,第三个参数只是让它在什么状态下触发。若是一个节点捕获和冒泡事件同时存在,谁在前谁先执行,和事件无关。对象
<div id="s1">s1 <div id="s2">s2</div> </div> <script> s1.addEventListener("click",function(e){ console.log("s1 冒泡事件"); //4️⃣ },false); s2.addEventListener("click",function(e){ console.log("s2 冒泡事件"); //2️⃣ },false); s1.addEventListener("click",function(e){ console.log("s1 捕获事件"); //1️⃣ },true); s2.addEventListener("click",function(e){ console.log("s2 捕获事件"); //3️⃣ },true); </script>
当我点击在s2
上面,触发顺序是s1捕获事件
> s2冒泡事件
> s2捕获事件
> s1冒泡事件
队列
事件代理:事件会在冒泡阶段向上传播到父节点,所以能够把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫作事件的代理(delegation)。
<ul id="colors"> <li>red</li> <li>yellow</li> <li>blue</li> <li>green</li> <li>black</li> <li>white</li> </ul> <script> var ul = document.querySelector('ul'); ul.addEventListener('click', function (event) { if (event.target.tagName.toLowerCase() === 'li') { // some code } }); </script>
来看一个具体例子:获取li
里面的文本,用事件流方法
var ul = document.querySelector('ul'); ul.addEventListener('click',showColor,false); function showColor(e){ var x = e.target; if(x.nodeName.toLowerCase() === 'li'){ console.log('The color is ' + x.innerHTML); } }
若是不使用事件代理,要获取li
里面的文本应该怎么弄呢?老方法是获取到全部子元素li
,遍历它就能够了
var colors = color-list.children for(var i=0;i<colors.length;i++){ colors[i].addEventListener('click',showColor,false); }; function showColor(e){ var x = e.target; console.log("The color is " + x.innerHTML); };
阻止事件再也不传播,能够使用事件对象的stopPropagation()
方法,但不会完全消除事件,若是说绑定多个事件的话。
用stopImmediatePropagation()
方法,绑定的其余事件也将不会执行。