文章目录
事件对象
获取事件对象
-
事件对象是什么?
也是个对象,这个对象里有事件触发时的相关信息
例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息 -
如何获取?
在事件绑定的回调函数的第一个参数就是事件对象
一般命名为event
、ev
、e
部分常用属性
type
获取当前的事件类型clientX
/clientY
获取光标相对于浏览器可见窗口左上角的位置offsetX
/offsetY
获取光标相对于当前DOM元素左上角的位置key
用户按下的键盘键的值
现在不提倡
使用keyCode
(已废弃)
img {
position: absolute;
top: 0;
left: 0;
}
img要用到绝对定位
<img src="./images/tianshi.gif" alt="">
<script>
let img = document.querySelector('img')
document.addEventListener('mousemove', function (e) {
// 不断得到当前的鼠标坐标
// 把坐标给图片(别忘了单位)
// img.style.left = '100px'
img.style.left = e.pageX - 50 + 'px'
img.style.top = e.pageY - 40 + 'px'
})
加上代码:
area.addEventListener('keyup', function (e) { //不要用keydown,键盘弹起的时候,再执行否则area里会接受enter字符,导致area.value=1
if (e.key == 'Enter') { //是enter键才行
send.click()
}
})
事件流
- 事件流指的是事件完整执行过程中的流动路径:先捕获后冒泡
事件捕获概念:
从DOM的根元素开始去执行对应的事件 (从外到里)
- 事件捕获需要写对应代码才能看到效果
- 代码:
DOM.addEventListener(时间类型,事件处理函数,是否使用捕获机制)
- 说明:
addEventListener
第三个参数传入true
代表是捕获阶段触发(很少使用
)
若传入false
代表冒泡阶段触发,默认就是false
若是用 L0 事件监听,则只有冒泡阶段,没有捕获
事件冒泡概念:
当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡
简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
事件冒泡是默认存在的
案例:
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
son.addEventListener('click', function () {
alert('我是儿子')
})
fa.addEventListener('click', function () {
alert('我是爸爸')
})
</script>
点击儿子区域,依次弹出:我是儿子,我是爸爸(传入true,则相反)
阻止事件流动:
因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
- 若想把事件就限制在当前元素内,就需要阻止事件流动
- 阻止事件流动需要拿到事件对象
- 语法:
事件对象.stopPropagation()
- 此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效
示例:
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function () {
alert('我是爸爸')
})
son.addEventListener('click', function (e) {
alert('我是儿子')
e.stopPropagation()
})
</script>
点击儿子区域,只弹出:我是儿子。
相同的鼠标经过事件:
mouseover
和 mouseout
会有冒泡效果
mouseenter
和 mouseleave
没有冒泡效果(推荐)
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('mouseover', function () {
console.log(111)
})
</script>
鼠标在父元素内,在父元素和子元素之间移动,会不断输出:111(改成mousenter
就好了)
两种(监听事件)注册事件的区别:
传统on注册(L0)
- 同一个对象,后面注册的事件会覆盖前面注册的事件(同一个事件)
- 直接
=null
(比如btn.onclick=null
),就可以实现事件的解绑 - 都是冒泡阶段执行的
事件监听注册(L2)
- 语法:
addEventListener
(事件类型, 事件处理函数, 是否使用捕获) - 后面注册的事件不会覆盖前面注册的事件(同一个事件)
- 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
- 如果要事件解绑,必须使用
removeEventListener
(事件类型, 事件处理函数, 获取捕获或者冒泡阶段) - 匿名函数无法被解绑
btn.addEventListener('click', add)
function add() { //给函数起名字,匿名函数无法解绑
alert('第一次')
}
btn.removeEventListener('click', add)
事件委托
事件委托是利用事件流的特征解决一些开发需求的知识技巧
总结:
- 优点:给父级元素加事件(可以提高性能)
- 原理:事件委托其实是利用事件冒泡的特点
- 实现:
事件对象.target
可以获得真正触发事件的元素
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
(e.target.style.color = 'red') //核心
})
</script>
学生信息表案例
难点在于删除怎么写,要用到事件委托,也就是监听整个大的tbody
,在寻找点击的删除属于tbody
中的哪一行数据。
如果用笨方法给每行添加监听,很难实现,而且性能不好。
没有想到用e.target.tagName
判断点击的是不是删除元素。还有给a加个id进行标记id="${i}"
来删除数组。
js代码:
// 1. 准备好数据后端的数据
let arr = [
{stuId: 1001, uname: '欧阳霸天', age: 19, gender: '男', salary: '20000', city: '上海'},
{stuId: 1002, uname: '令狐霸天', age: 29, gender: '男', salary: '30000', city: '北京'},
{stuId: 1003, uname: '诸葛霸天', age: 39, gender: '男', salary: '2000', city: '北京'},
]
// 获取父元素 tbody
let tbody = document.querySelector('tbody')
// 添加数据按钮
// 获取录入按钮
let add = document.querySelector('.add')
// 获取各个表单的元素
let uname = document.querySelector('.uname')
let age = document.querySelector('.age')
let gender = document.querySelector('.gender')
let salary = document.querySelector('.salary')
let city = document.querySelector('.city')
// 渲染函数 把数组里面的数据渲染到页面中
function render() {
// 先干掉以前的数据 让tbody 里面原来的tr 都没有
tbody.innerHTML = ''
// 在渲染新的数据
// 根据数据的条数来渲染增加 tr
for (let i = 0; i < arr.length; i++) {
// 1.创建tr
let tr = document.createElement('tr')
// 2.tr 里面放内容
tr.innerHTML = `
<td>${arr[i].stuId}</td>
<td>${arr[i].uname}</td>
<td>${arr[i].age}</td>
<td>${arr[i].gender}</td>
<td>${arr[i].salary}</td>
<td>${arr[i].city}</td>
<td>
<a href="javascript:" id="${i}">删除</a>
</td>
`
// 3.把tr追加给 tobdy 父元素.appendChild(子元素)
tbody.appendChild(tr)
}
}
// 页面加载就调用函数
render()
add.addEventListener('click', function () {
// alert(11)
// 获得表单里面的值 之后追加给 数组 arr 用 push方法
arr.push({
// 得到数组最后一条数据的学号 1003 + 1
stuId: arr[arr.length - 1].stuId + 1,
uname: uname.value,
age: age.value,
gender: gender.value,
salary: salary.value,
city: city.value
})
// console.log(arr)
// 重新渲染我们的函数
render()
// 复原所有的表单数据
uname.value = age.value = salary.value = ''
gender.value = '男'
city.value = '北京'
})
// 删除操作, 删除的也是数组里面的数据 , 但是我们用事件委托(难点!!!)
tbody.addEventListener('click', function (e) {
// alert(11)
// 我们只能点击了链接 a ,才会执行删除操作
// 那我们怎么知道你点击了a呢?
// 俺们只能点击了链接才能做删除操作
// console.dir(e.target.tagName)
if (e.target.tagName === 'A') {
// alert('你点击了链接')
// 删除操作 删除 数组里面的数据 arr.splice(从哪里开始删,1) 给a加个id进行标记id="${i}"
// 我要得到a的id 需要
// console.log(e.target.id)
arr.splice(e.target.id, 1)
// 重新渲染我们的函数
render()
}
})