事件对象
+ 当一个事件触发的时候, 对本次事件的描述
+ 例子: 客服
=> 当电话响的时候, 接起来, 聊
=> 在接电话的时候, 需要记录一些信息
-> 什么地方打来的
-> 说了什么事情
-> 需要什么帮助
-> 什么时间
-> ...
+ 例子: 鼠标按下行为
=> 当你在浏览器上触发点击行为的时候, 要执行事件处理函数
=> 需要一些新来来记录
-> 你点击的是哪一个元素
-> 你点击的坐标是什么
-> 你按下的是哪一个按键
-> 你当前触发的事件类型是什么
+ 例子: 键盘事件
=> 当你在按下键盘的时候触发
=> 需要记录一些信息
-> 按下的是哪一个按键
-> 你按下的是不是组合按键
如何获取事件对象
+ 标准浏览器
=> 直接在事件处理函数上接受一个形参
=> 会在事件触发的时候,由浏览器自动传递实参
+ IE 低版本
=> 不需要接收形参
=> 直接使用 window.event
-> 在标准浏览器下也可以使用了
-> 官方给的还是兼容
+ 书写一个兼容方式
=> 短路表达式
=> e = e || window.event
<style>
div{
width: 200px;
height: 200px;
background-color: #ccc;
}
</style>
<div id="box"></div>
<script src="./utils.js"></script>
// 标准浏览器
// 0. 获取元素
var div = document.querySelector('div')
// 1. 绑定事件
div.onclick = function(e){
// 每一次事件触发, 都会获取一个最新的事件对象
// 对当前这一次事件的描述
// console.log(window.event)
// console.log(e)
// 兼容
e = e || window.event
console.log(e)
}
div.addEventListener('click', function(ev){
console.log(ev)
})
// IE 低版本
// 0. 获取元素
var div = document.getElementById('box')
// 绑定事件
div.onclick = function(){
console.log(window.event)
}
div.attachEvent('onclick', function(){
console.log(window.event)
})
试一下我们自己封装的 on 函数,也是可以用的
// 0. 获取元素
var div = document.querySelector('div')
on(div, 'click', function(e){
// 处理时间对象兼容
e = e || window.event
console.log(e)
})
鼠标事件的事件对象信息
鼠标事件的事件对象信息
+ 事件对象里面和鼠标事件相关的一些信息
1. 按下的按键
+ 事件对象中有一个叫做 button 的属性
+ 他来表示你按下的是哪一个按键
=> 0 表示左键
=> 1 表示滚轮键
=> 2 表示右键
2. 光标的坐标(重点)
+ 适用任何鼠标事件
2-1. clientX 和 clientY
=> 光标距离可视窗口左上角的位置
2-2. pageX 和 pageY
=> 光标距离文档流左上角的位置
2-3. offsetX 和 offsetY
=> 光标距离元素左上角的位置
=> 注意: 元素: 光标触发事件的元素(不是事件源)!
=> 扩展: 如果你不想按照光标触发元素的左上角计算坐标, 想按照事件源来计算坐标
-> 使用 css 样式: pointer-events:none
-> 纯靠 JS 完成
-> 1. offsetParent 是谁
-> 获取偏移量的时候的参考父级元素
-> 根据 body 来
-> + offsetLeft - 父元素的 offsetLeft
-> 根据 父元素
-> + offsetLeft
<style>
*{
margin: 0;
padding: 0;
}
body{
width: 2000px;
height: 2000px;
}
div{
width: 100px;
height: 100px;
background-color: pink;
margin: 50px;
overflow: hidden;
}
p{
width: 50px;
height: 50px;
background-color: #ccc;
margin: 30px;
/* 在你计算坐标的时候,不要考虑我 */
pointer-events: none;
}
</style>
<div>
<p></p>
</div>
// 0. 获取元素
var div = document.querySelector('div')
// 1. 绑定鼠标按下事件
div.onmousedown = function(e){
// 处理事件对象兼容
e = e || window.event
// 2-1. clientX 和 clientY
console.log('clientX', e.clientX)
console.log('clientY', e.clientY)
// 2-2. pageX 和 pageY
console.log('================')
console.log('pageX', e.pageX)
console.log('pageY', e.pageY)
// 2-3. offsetX 和 offsetY
console.log('offsetX', e.offsetX)
console.log('offsetY', e.offsetY)
// console.log(e.offsetX + p.offsetLeft - div.offsetLeft)
// console.log(e.offsetY + p.offsetTop - div.offsetTop)
}
练习1: 实时显示光标坐标点
1. 获取元素
=> span.x
=> span.y
2. 绑定事件
=> 绑定什么事件? mousemove
-> 只要移动就会触发
=> 给谁绑定? document
-> 整个文档都得触发
3. 获取坐标点
=> pageX 和 pageY
=> clientX 和 clientY?
-> 如果没有滚动条无所谓
-> 一旦有了滚动条,那么你拿到的都是相对于可视窗口的
=> offsetX 和 offsetY?
-> 因为你的页面里面一定会有别的东西
-> 不合适
<h1>X 轴坐标点: <span class="x">0</span></h1>
<h1>Y 轴坐标点: <span class="y">1</span></h1>
// 1. 获取元素
var spanX = document.querySelector('.x')
var spanY = document.querySelector('.y')
// 2. 绑定事件
document.addEventListener('mousemove', function(e){
// 处理事件对象兼容
e = e || window.event
// 3. 获取坐标点
var x = e.pageX
var y = e.pageY
spanX.innerText = x
spanY.innerText = y
})
练习2: 鼠标跟随
鼠标跟随
1. 获取元素
=> div
=> p
2. 绑定事件
=> mouseover: 移入 p 显示
=> mouseout: 移出 p 隐藏
=> mousemove: 移动的时候, p 随时动
3. move 事件处理函数里面
=> 获取坐标点
=> pageX 和 pageY?
-> 对于只有没有滚动条的页面适用
=> offsetX 和 offsetY?
-> 因为根据元素计算坐标
-> 除非你的提示框和标题是父子关系,并且是根据标题来定位
=> clientX 和 clientY
-> 针对我们现在的布局,是适用的
4. 解决闪烁问题
=> 为什么?
-> 当提示盒子显示的时候, 光标相当于移出了 div
-> 就要让 p 消失
-> 消失的瞬间, 我的 div 又被触发了移入
-> 就要让 p 显示
=> 怎么解决?
-> 让 p 和光标离开一些距离
<style>
*{
margin: 0;
padding: 0;
}
body{
height: 2000px;
}
div{
width: 200px;
height: 200px;
border: 2px solid #333;
margin: 100px;
}
p{
width: 200px;
height: 100px;
background-color: #fff;
border: 1px solid #333;
position: absolute;
left: 0;
top: 0;
display: none;
}
p.active{
display: block;
}
</style>
<div>
我是一个标题
</div>
<p>
我是提示文本我是提示文本我是提示文本我是提示文本我是提示文本我是提示文本
</p>
// 1. 获取元素
var div = document.querySelector('div')
var p = document.querySelector('p')
// 2. 绑定事件
div.addEventListener('mouseover', function(){
// p 显示
p.classList.add('active')
})
div.addEventListener('mouseout', function(){
// p 隐藏
p.classList.remove('active')
})
div.addEventListener('mousemove', function(e){
// 处理事件对象兼容
e = e || window.event
// 3. 获取坐标点
var x = e.clientX + 5
var y = e.clientY + 5
// 4. 给 p 的 left 和 top 赋值
p.style.left = x + 'px'
p.style.top = y + 'px'
})
组合
<style>
body{
height: 2000px;
}
p{
width: 150px;
height: 50px;
background-color: rgba(255, 255, 255, 0);
position: absolute;
left: 0;
top: 0;
}
</style>
<body>
<p>
X 轴坐标点: <span class="x">0</span>
<br>
Y 轴坐标点: <span class="y">1</span>
</p>
<script>
/*
实时显示光标坐标点 + 鼠标跟随
1. 获取元素
=> span.x
=> span.y
=> p
2. 绑定事件
=> 绑定什么事件?
-> mouseover: 移入 p 显示
-> mouseout: 移出 p 隐藏
-> mousemove: 移动的时候, p 随时动
=> 给谁绑定? document
-> 整个文档都得触发
3. move 事件处理函数里面
3-1. 获取光标坐标点
=> pageX 和 pageY
3-2. 获取显示框 p 坐标点
=> clientX 和 clientY
*/
// 1. 获取元素
var spanX = document.querySelector('.x')
var spanY = document.querySelector('.y')
var p = document.querySelector('p')
// 2. 绑定事件
document.addEventListener('mousemove', function(e){
// 处理事件对象兼容
e = e || window.event
// 3-1. 获取光标坐标点
var pageX = e.pageX
var pageY = e.pageY
spanX.innerText = pageX
spanY.innerText = pageY
// 3-2. 获取显示框 p 坐标点
var x = e.clientX
var y = e.clientY
// 4. 给 p 的 left 和 top 赋值
p.style.left = x + 'px'
p.style.top = y + 'px'
})
</body>
设置body高度后,提示框会随着滚动条向上移动…
详细见这里!!!
简单测试也没什么问题,但是clientX与clientY获取的是相对于当前浏览器窗口的坐标,忽略页面滚动因素,这在很多条件下很有用,但当我们需要考虑页面滚动,也就是相对于文档(body元素)的坐标时怎么办呢?
=> 加上卷去的高/宽度就可以了。
// 3-2. 获取显示框 p 坐标点
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
var x = e.clientX + scrollLeft
var y = e.clientY + scrollTop
练习3: 判断移入角度
0. 布局
=> 显示内容
=> 遮罩层
1. 获取元素
1-1. .content: 判断进入角度
1-2. .mask: 瞬间定位, 移动
2. 绑定事件
2-1. mouseover
-> 获取坐标:
-> 相对于屏幕确定的坐标原点
-> 要想根据坐标原点拿到一个坐标系里面的位置,就要使用 clientX 和 clientY
2-2. 确定坐标原点
-> 元素的 offsetLeft + 元素宽度的一半
2-3. 获取根据坐标原点来的坐标
2-4. 根据坐标计算进入的角度
-> JS 拿不到角度, 只能拿到一个弧度
-> Math.atan2(y, x) 弧度
-> 1度 = 1弧度 * (180 / PI)
-> 得到的角度是 0 ~ 90 ~ 180 ~ -90 ~ 0
-> 为了方便判断, 我们计算一下
=> 给每一个角度 + 180
2-5. 瞬间定位 mask 盒子
-> 根据不同的进入角度, 来定位到不同的位置
2-6. 移入到 content 里面
-> left 0 top 0
-> 直接设置
-> 因为代码执行会比 dom 操作要快
-> 定时器: 设置一个 16ms
-> 延后执行一下 '进入'
2-7. 问题:
-> 下一次移入的时候
-> 第一次移入的时候,设置了一个 transition
-> 第二次移入的时候, 应该是瞬间定位, 但是你有 transition
-> 解决问题: 在每次瞬间定位之前, 把 transition 干掉
2-8. 移出事件 mouseout
-> 和之前的一模一样
思路:
2-2. 确定坐标原点 (originX, originY)
2-4. 获取根据坐标原点来的坐标后, 根据坐标计算进入的角度, 除以90将它分成 4 个部分(0, 1, 2, 3),方便判断
再% 4, 使 0 和 4 统一为一部分
// 0: 左边
// 1: 上边
// 2: 右边
// 3: 下边
<style>
*{
margin: 0;
padding: 0;
}
.content{
width: 300px;
height: 300px;
line-height: 300px;
text-align: center;
font-size: 30px;
border: 1px solid #333;
margin: 300px;
position: relative;
overflow: hidden;
}
.mask{
width: 300px;
height: 300px;
position: absolute;
left: 0;
top: -100%;
background-color: rgba(251, 251, 120, 0.5);
pointer-events: none;
}
.x{
width: 600px;
height: 1px;
background-color: red;
position: absolute;
left: 100px;
top: 451px;
}
.y{
width: 1px;
height: 600px;
background-color: red;
position: absolute;
left: 451px;
top: 100px;
}
</style>
<!-- <p class="x"></p>
<p class="y"></p> -->
<div class="content">
盒子内部显示的内容
<!-- 遮罩层 -->
<div class="mask"></div>
</div>
// 1. 获取元素
var content = document.querySelector('.content')
var mask = document.querySelector('.mask')
// 2. 绑定事件
// 2-1. 鼠标移入事件
content.addEventListener('mouseover', function(e){
// 处理事件对象兼容
e = e || window.event
// 2-2. 确定坐标原点
var originX = content.offsetLeft + content.offsetWidth / 2
var originY = content.offsetTop + content.offsetHeight / 2
// console.log(originX, originY)
// 2-3. 获取根据坐标原点来的坐标
var mouseX = e.clientX - originX
var mouseY = e.clientY - originY
// 2-4. 计算角度
var deg = Math.atan2(mouseY, mouseX) * (180 / Math.PI)
// console.log(deg)
// 2-4. 为了方便判断, 计算一下
var degNum = Math.round((deg + 180)/ 90) % 4
// 0: 左边
// 1: 上边
// 2: 右边
// 3: 下边
// console.log(degNum)
// 2-7. 每次瞬间定位之前, 把 transition 干掉
mask.style.transition = null
// 2-5. 根据进入角度定位 mask 盒子
switch(degNum){
case 0:
mask.style.left = '-100%'
mask.style.top = 0
break
case 1:
mask.style.left = 0
mask.style.top = '-100%'
break
case 2:
mask.style.left = '100%'
mask.style.top = 0
break
case 3:
mask.style.left = 0
mask.style.top = '100%'
break
}
// 2-6. 让 mask 盒子移入
setTimeout(function(){
mask.style.transition = 'all .5s linear'
mask.style.left = 0
mask.style.top = 0
}, 16)
})
// 2-8. 鼠标移出事件
content.addEventListener('mouseout', function(e){
// 处理事件对象兼容
e = e || window.event
// 获取根据原点坐标来的坐标
var originX = content.offsetLeft + content.offsetWidth / 2
var originY = content.offsetTop + content.offsetHeight / 2
// console.log(originX, originY)
// 获取根据坐标原点来的坐标
var mouseX = e.clientX - originX
var mouseY = e.clientY - originY
// 计算角度
var deg = Math.atan2(mouseY, mouseX) * (180 / Math.PI)
// console.log(deg)
// 为了方便判断, 计算一下
var degNum = Math.round((deg + 180)/ 90) % 4
// 判断移出的角度来决定 mask 的位置
switch(degNum){
case 0:
mask.style.left = '-100%'
mask.style.top = 0
break
case 1:
mask.style.left = 0
mask.style.top = '-100%'
break
case 2:
mask.style.left = '100%'
mask.style.top = 0
break
case 3:
mask.style.left = 0
mask.style.top = '100%'
break
}
})
键盘事件的事件对象信息
1. 按下的是哪一个按键
1-1. 事件对象里面有一个 key 的属性
=> 表示你按下的那个按钮
=> 特性: IE 低版本不支持
=> 不常用
1-2. 事件对象里面有一个叫做 keyCode 的属性
=> 表示你按下的是哪一个按键, 但是是以编码的形式给你
=> 特性: FireFox < 20 的版本不支持
=> 在火狐低版本使用 which 属性
=> 兼容: var code = e.keyCode || e.which
// 0. 获取元素
var inp = document.getElementById('inp')
// 1. 绑定一个键盘按下的事件
inp.addEventListener('keydown', function(e){
// 处理事件对象兼容
e = e || window.event
// 1-1. key 属性
console.log(e.key)
// 1-2. keyCode 属性
console.log(e.keyCode)
console.log(e.which)
if(e.keyCode === 65){
console.log('你按下的是 a')
}
})
2. 你按下的是不是组合按键
2-1. altKey
2-2. ctrlKey
2-3. shiftKey
2-4. metaKey
+ 四个属性的值都是布尔值
=> altKey 表示 alt 键 在 mac 里代表 options 键
=> ctrlKey 表示 ctrl 键
=> shiftKey 表示 shift 键
=> metaKey 表示 win 键 在 mac 里代表 command 键
-> IE 没有,不支持 metaKey
+ 当你按下一个按键的时候
=> 如果这四个的某一个的值是 true, 表示你同时也按下了这个按键
// 0. 获取元素
var inp = document.getElementById('inp')
// 2. 组合按键
inp.addEventListener('keydown', function(e){
e = e || window.event
// console.log(e)
// 判断按下的是 shift + a
if(e.shiftKey && e.keyCode === 65){
console.log('你按下的是 shift + a')
}
// 多个一起判断
if(e.shiftKey && e.ctrlKey && e.altKey && e.keyCode === 65){
console.log('你按下的是 shift + ctrl + alt + a')
}
})