目录
一、事件流
(一)事件流与两个阶段说明
事件流是指事件完整执行过程中的流动路径 就少访问那些标签是有一定流程的 不是写个 div 就直接访问的 div 标签的
包括捕获(从城市回村里——由大标签到小标签)和冒泡(从村里去城市——由小标签到大标签)
1.事件捕获
父亲到儿子 从DOM 的根元素开始执行对应的事件
要进行事件捕获要有对应的捕获值才能看到结果 就是下面第三个值
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
下面本来是 先儿子 再父亲 最后爷爷的顺序输出警示框
使用捕获机制后 先爷爷 再父亲 最后儿子 顺序变了(下面都是同名事件)
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
const fa = document.querySelector('.father')
const son = document.querySelector('.son')
document.addEventListener('click', function () {
alert('我是爷爷')
}, true)
fa.addEventListener('click', function () {
alert('我是父亲')
}, true)
son.addEventListener('click', function () {
alert('我是儿子')
}, true)
</script>
</body>
2.事件冒泡
儿子到父亲 当一个事件被触发时,它的祖先元素的同名事件会被依次触发
实际工作都是冒泡为主,把刚才捕获中的 第三个值去掉了就变成默认的冒泡方式了
事件冒泡是默认存在的
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
const fa = document.querySelector('.father')
const son = document.querySelector('.son')
document.addEventListener('click', function () {
alert('我是爷爷')
})
fa.addEventListener('click', function () {
alert('我是父亲')
})
son.addEventListener('click', function () {
alert('我是儿子')
})
</script>
</body>
[点击并拖拽以移动]
(二)阻止冒泡
有时候冒泡并不好容易导致事件影响父级元素,所以我们要阻止冒泡,
想把事件限制在当前元素内,就需要阻止冒泡
阻止事件冒泡需要提前拿到事件对象
语法:阻止流动传播(既能阻止冒泡也能阻止捕获)
e 别忘了 事件对象
<body>
<script>
事件对象.stopPropagation()
</script>
</body>
下面本来应该按照事件冒泡方式的三个同名事件,结果在儿子那儿被阻断了 ,只显示我是儿子
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
const fa = document.querySelector('.father')
const son = document.querySelector('.son')
document.addEventListener('click', function () {
alert('我是爷爷')
})
fa.addEventListener('click', function () {
alert('我是父亲')
})
son.addEventListener('click', function (e) {
alert('我是儿子')
e.stopPropagation()
})
</script>
</body>
(三)解绑事件 / 事件移除
解除不想要的事件
1.level 0 的 DOM 语法
解除事件后 下面点击按钮没反应
<body>
<button>点击</button>
<script>
const btn = document.querySelector('button')
btn.onclick = function () {
alert('已点击')
}
btn.onclick = null
</script>
</body>
2.level 2 的 DOM 语法
首先匿名函数无法解除事件
<body>
<button>点击</button>
<script>
const btn = document.querySelector('button')
function fn() {
alert('已点击')
}
btn.addEventListener('click', fn)
btn.removeEventListener('click', fn)
</script>
</body>
鼠标经过事件的区别
mouseover 和 mouseout 有冒泡效果
一经过孩子 事件会冒泡到父亲上
mouseenter 和 mouseleave 没有冒泡效果 (推荐使用)
(四)两种注册事件的区别
1.传统on注册( L0 )
同一个对象后面注册的事件会覆盖前一个事件(同一个事件)
可以用 null 覆盖实现事件的解绑
都是冒泡阶段执行 没有捕获阶段
2.事件监听注册( L1 )
语法: addEventListener(事件类型,事件处理函数,是否使用捕获)
后面不会覆盖前面注册的事件
可以冒泡也可以捕获 通过使用第三个参数使用
必须用 removeeventlistener(事件类型,事件处理函数,是否使用捕获) 来解绑事件
匿名函数无法解绑
二、事件委托
利用事件流的特征解决一些开发需求的知识技巧,可以减少注册次数,可以提高程序性能。
就是把事件委托给别人完成
给父亲注册事件,当我们触发子元素的事件时,会冒泡到父元素身上,从而触发父元素的事件
原理:利用了事件冒泡的特点
下面的例子:点击孩子 li 孩子没有点击事件 但是点击后事件会冒泡到父亲 ul 的事件上 所以会显示11
<body>
<ul>
<li>第1个孩子</li>
<li>第2个孩子</li>
<li>第3个孩子</li>
<li>第4个孩子</li>
<li>第5个孩子</li>
</ul>
<script>
const ul = document.querySelector('ul')
ul.addEventListener('click',function(){
alert(11)
})
</script>
</body>
事件委托当点击 li 标签时里面的文字变红,点击 p 标签时不变色 利用事件对象 e 的属性来控制
e 是 click 点击的对象 这样就能找到真正触发的事件对象
<body>
<ul>
<li>第1个孩子</li>
<li>第2个孩子</li>
<li>第3个孩子</li>
<li>第4个孩子</li>
<li>第5个孩子</li>
<p>我不变色</p>
</ul>
<script>
const ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
if (e.target.tagName === 'LI') {
e.target.style.color = 'red'
}
})
</script>
</body>
三、阻止默认行为
和阻止冒泡比较像,但是这个是阻止默认的行为,比如跳转标签,
下面的例子本,点击按钮会跳转到百度界面,但是添加了阻止默认行为 e.preventDefaule() 就不能再跳转到百度了直接没反应了
<body>
<form action="http://www.baidu.com">
<input type="submit" value="去百度">
</form>
<script>
const form = document.querySelector('form')
form.addEventListener('submit', function (e) {
e.preventDefault()
})
</script>
</body>
四、其他事件
(一)页面加载事件
加载外部资源 如图片外联css Javascript 加载完毕后触发的事件
等页面资源全部加载完了再做一些事情。之前喜欢把 script 代码写在 head 中,这时直接找 dom 元素找不到
1.事件名:load
监听页面所有资源加载完毕:
window 比 document 还大
给 window 添加 load 事件就能监听 页面是否加载完毕
然后在函数里面添加 想要执行的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.addEventListener('load', function () {
})
</script>
</head>
<body>
</body>
</html>
2.事件名:DOMcontentLoaded
和上一个不同之处在于 这个是监听所有 dom 元素加载完 速度快一点
document.addEventListener('DOMcontentLoaded', function(){
})
(二)页面滚动事件
1.基本使用
滚动条在滚动时持续触发的事件,想让用户滚动到某个区域时做一些动作,比如固定导航栏,返回顶部等。
事件名:scroll
下面例子一滚动就触发 打印我正在滚动,监听整个页面的滚动效果,就监听 window 对象
<body>
<script>
window.addEventListener('scroll',function(){
console.log('我正在滚动')
})
</script>
</body>
2.获取位置
想要元素滚动的大小,就用这两个元素
scrollLeft:被卷去的头部 就是拉动滚动条 下面的文字会往上面移动 上面移出显示元素界面的部分就是,被卷去的头部
scrollTop:被卷去的左侧 同理
获得页面的 HTML 元素 不能通过 document.html 获取 而是 document.documentElement 获取 html 元素 它的 scrollTop 元素可以被赋值 就是 document.documentElement.scrollTop = 800 后面接数值 不加单位
这样就能拿到页面滚动的值了
<body>
<script>
window.addEventListener('scroll', function () {
console.log(document.documentElement.scrollTop)
})
</script>
</body>
应用:让 div 盒子 在顶部被卷去大于等于 100px 时显示出来
<body>
<div>
我是一段文字我内容很多
我是一段文字我内容很多
我是一段文字我内容很多
我是一段文字我内容很多
我是一段文字我内容很多
我是一段文字我内容很多
我是一段文字我内容很多
</div>
<script>
const div = document.querySelector('div')
window.addEventListener('scroll', function () {
let n = document.documentElement.scrollTop
if (n >= 100) {
div.style.display = 'block'
} else {
div.style.display = 'none'
}
})
</script>
</body>
(三)页面尺寸事件
1.介绍
在浏览器窗口尺寸改变时触发事件
事件语法:resize
<body>
<div></div>
<script>
const div = document.querySelector('div')
console.log(div.clientWidth)
window.addEventListener('resize', function () {
console.log(1)
})
</script>
</body>
2.获得元素尺寸位置
client 方法
获得元素宽高:不包含 border 边框 margin 也不包括 包含 padding
clientWidth
clientHight
offset 方法
offsetWidth
offsetHeight
这俩获得的元素自身的宽高包含 边框 得到的是数值有利于计算
注意获得的是可视的宽高 如果盒子隐藏 获得的结果是 0
offsetLeft 距左边边框的距离 如果父亲有定位则结果是距父亲的距离
offsetTop 元素是距最上面边框的距离 如果页面滚动了还是距原来页面最上面的距离
<body>
<div></div>
<script>
const div = document.querySelector('div')
console.log(div.offsetLeft)
</script>
</body>
getBoundingClientRect() 方法
也能得到盒子和边框的距离,但是这个方法对于整个页面来说是根据视口定位得到的距离,就是页面进行滚动时,这个方法得到的距离顶底和两侧的距离会发生变化,不是根据原来最开始的位置来计算的。
<body>
<div></div>
<script>
const div = document.querySelector('div')
console.log(div.getBoundingClientRect())
</script>
</body>
练习:轮播图改良版
界面展示:
代码部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 400px;
height: 200px;
}
.top {
height: 50px;
}
.zuo {
float: left;
width: 160px;
height: 50px;
background-color: red;
}
ul {
float: right;
width: 240px;
height: 50px;
background-color: pink;
}
li {
padding-right: 10px;
width: 40px;
float: right;
list-style: none;
}
.bottom {
height: 150px;
}
.box1 {
float: left;
width: 100px;
height: 100%;
}
.box2 {
float: left;
width: 300px;
height: 100%;
}
img {
width: 100%;
height: 100%;
}
.bottom {
display: none;
}
.active {
color: red;
}
.dong {
display: block;
}
</style>
</head>
<div class="box">
<div class="top">
<div class="zuo">每日特价</div>
<ul>
<li><a class="active" href="#" data-id="0">精选</a></li>
<li><a href="#" data-id="1">美食</a></li>
</ul>
</div>
<div class="btm">
<div class="bottom dong">
<div class="box1"><img src="1.png" alt=""></div>
<div class="box2"><img src="3.png" alt=""></div>
</div>
<div class="bottom">
<div class="box1"><img src="2.png" alt=""></div>
<div class="box2"><img src="4.png" alt=""></div>
</div>
</div>
</div>
<body>
<script>
const ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
document.querySelector('ul .active').classList.remove('active')
e.target.classList.add('active')
const i = +e.target.dataset.id
document.querySelector('.btm .dong').classList.remove('dong')
document.querySelector(`.btm .bottom:nth-child(${i+1})`).classList.add('dong')
}
})
</script>
</body>
</html>
练习:页面滚动一定长度显示顶部栏
界面展示:
代码部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
height: 3000px;
}
.header {
position:fixed;
top: -100px;
width: 100%;
height: 100px;
background-color: red;
text-align: center;
line-height: 100px;
}
.neirong {
overflow: hidden;
height: 800px;
background-color: pink;
width: 80%;
margin: 0 auto;
}
.sk {
width: 200px;
height: 100px;
background-color: blue;
margin-top: 200px;
}
</style>
</head>
<body>
<div class="header">首页</div>
<div class="neirong">
<div class="sk"></div>
</div>
<script>
const sk = document.querySelector('.sk')
const neirong = document.querySelector('.neirong')
const header = document.querySelector('.header')
document.addEventListener('scroll', function () {
const n = document.documentElement.scrollTop
if ( n >= sk.offsetTop ){
header.style.top = 0
}else{
header.style.top = '-100px'
}
})
</script>
</body>
</html>