之前总结了事件捕获和冒泡以及阻止事件传播,今天写一下事件代理方面的总结
DOM 事件之捕获、冒泡:
阻止事件传播:
事件代理
监听列表中多项 li 时,实现点击 li 控制台打印对应文本,如下:
<ul class="ct">
<li>苹果</li>
<li>香蕉</li>
<li>葡萄</li>
</ul>
首先想到的对每一个 li 进行监听
let ct = document.querySelector('.ct')
for(let i = 0; i < ct.children.length; i++){
ct.children[i].onclick = function(e){
console.log(e.target.textContent)
}
}
或者
let ct = document.querySelector('.ct')
for(let i = 0; i < ct.children.length; i++){
ct.children[i].addEventListener('click',function(e){
console.log(e.target.textContent)
})
}
使用onclick
和addEventListener
的区别:onclick
是属性,addEventListener
是方法。
简单来说,如果使用onclick
,如果此元素需要同时添加多个onclick
事件,那么之前的onclick
会被覆盖,而使用addEventListener
添加的事件相当于调用它,并传递相应的参数。
如果此时 li 是动态生成的,每一个li 都要给它添加监听器,监听器多了会特别占内存,从而影响性能,这里最好的方式是使用事件代理。
举个简单的例子:大学宿舍同学,买的快递都到了,这时有两种方法,一种是每个人都去取自己的快递,另一种方法是大家找一个同学,让他统一去取快递,然后在发给每一个同学。
这里取快递就是一个事件,第一种方法就是相当于给每个元素添加事件,第二种方法统一去取快递的同学就是代理元素。
使用事件代理来实现它,监听的元素应该是这些元素的父元素,当我点击父元素内的元素时,父元素都会得到响应,并分发相应的事件。e.target
就是点击的元素。
let ct = document.querySelector('.ct')
ct.addEventListener('click', function(e) {
console.log(e.target.textContent)
})
用事件代理操作一些比较复杂的事情,比如下面代码,当我点击开头添加,则在<li>苹果</li>
前添加input
内的内容,如果我点结尾添加<li>葡萄</li>
后添加input
内的内容。
<ul class="ct">
<li>苹果</li>
<li>香蕉</li>
<li>葡萄</li>
</ul>
<div class="content">
<input class="ipt-add-content" placeholder="添加内容" />
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
</div>
这里事件代理元素是content
,如按照上面的方法,给每个子元素分发事件,那么当我点击input
时,也会触发click
事件,这就偏离了我们的需求。所以这里需要做一个判断,只有点开头添加
或者结尾添加
才能添加到相应的位置,点其他地方一律不操作。
在这里需要注意e.currentTarget
和e.target
的区别:e.currentTarget
:添加事件的元素e.target
:执行事件的元素
大部分事件中这两者没什么区别,但在click
事件中,如果使用事件代理,这两个指向的就不是同一个元素。
let ct = document.querySelector('.ct')
let addContent = document.querySelector('.ipt-add-content')
let content = document.querySelector('.content')
content.addEventListener('click', function(e) {
let li = document.createElement('li')
li.textContent = addContent.value
if(e.target.textContent === '开头添加'){ //只有点'开头添加'才执行
ct.insertBefore(li,ct.firstChild)
}else if(e.target.textContent === '结尾添加'){//只有点'结尾添加'才执行
ct.appendChild(li)
}
})
常用的 HTML 事件
鼠标事件
mousedown
:鼠标按下触发,其中button
属性监测鼠标按下哪个键:0
是鼠标左键,1
鼠标中间的滚轮,2
鼠标右键。mouseup
:鼠标松开触发,其中button
属性监测鼠标按下哪个键:0
是鼠标左键,1
鼠标中间的滚轮,2
鼠标右键。mousemove
:鼠标移动触发click
:点击事件dblclick
:双击事件mousewheel
:鼠标滚动事件,wheelDelta
可以判定鼠标滚动方向,180 向上滚动,-180 向下滚动mouseover
:鼠标进入触发,会冒泡,如果监听的是父元素,鼠标移入到父元素内的子元素也会触发mouseout
:鼠标离开触发,会冒泡,如果监听的是父元素,鼠标从父元素内的子元素移出也会触发movseenter
:鼠标进入触发,不会冒泡mouseleave
:鼠标离开触发,不会冒泡
注:
-
clientX
,clientY
客户端坐标位置,当事件发生时,鼠标的位置 -
pageX
,pageY
页面坐标位置,发生事件的页面坐标 -
screenX
,screenY
事件发生时相对屏幕的坐标 - 修改键:
shift
、ctrl
、alt
、win
对应的修改键状态shiftKey
、ctrlKey
、altKey
、metaKey
,他们是布尔值,按下为true
,松开为false
。
触摸事件
touchstart
:手指点击触发,点击坐标在touches[0]
里面,因为手机支持多点触控touchend
:手指离开触发,同上touchmove
:手指移动触发,同上
键盘事件:
keydown
:键盘上按下任意键触发,按住不放会重复触发,文本框变化之前触发keyup
:键盘上释放任意键触发keypress
:键盘上按下任意字符键触发,按住不放会重复触发,文本框变化之前触发
注:
-
textInput
和keypress
类似,书上说textInput
只能在可编辑区域触发,只能按下有效字键才能触发(enter
键无法触发,ctrl+v
可以触发),keypress
按下任何影响文本显示的键都会触发(enter
键可以触发,ctrl+v
无法触发),但我操作下来,发现这两者并没有什么区别。 -
location
属性4
表示设备键盘
页面相关事件:
load
:加载完成时触发move
:浏览器窗口被移动时触发resize
:浏览器的窗口大小被改变时触发scroll
:滚动条位置发生变化时触发
表单相关事件
blur
:元素失去焦点时触发change
:元素失去焦点且元素内容发生改变时触发focus
:元素获得焦点时触发reset
:表单中reset属性被激活时触发submit
:表单被提交时触发input
:在input
元素内容修改后立即被触发
编辑事件
beforecopy
:当页面当前的被选择内容将要复制到浏览者系统的剪贴板前触发此事件beforecut
:当页面中的一部分或者全部的内容将被移离当前页面(剪贴)并移动到浏览者的系统剪贴板时触发此事件beforeeditfocus
:当前元素将要进入编辑状态beforepaste
:内容将要从浏览者的系统剪贴板传送(粘贴)到页面中时触发此事件beforeupdate
:当浏览者粘贴系统剪贴板中的内容时通知目标对象contextmenu
:当浏览者按下鼠标右键出现菜单时或者通过键盘的按键触发页面菜单时触发的事件copy
:当页面当前的被选择内容被复制后触发此事件cut
:当页面当前的被选择内容被剪切时触发此事件losecapture
:当元素失去鼠标移动所形成的选择焦点时触发此事件paste
:当内容被粘贴时触发此事件select
:当文本内容被选择时的事件selectstart
:当文本内容选择将开始发生时触发的事件
拖动事件
drag
:当某个对象被拖动时触发此事件 (活动事件)dragdrop
:一个外部对象被鼠标拖进当前窗口时触发dragend
:当鼠标拖动结束时触发此事件dragenter
:当对象被鼠标拖动的对象进入其容器范围内时触发此事件dragleave
:当对象被鼠标拖动的对象离开其容器范围内时触发此事件dragover
:当某被拖动的对象在另一对象容器范围内拖动时触发此事件dragstart
:当某对象将被拖动时触发此事件drop
:在一个拖动过程中,释放鼠标键时触发此事件
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。