事件的相关内容

文章详细介绍了JavaScript中的事件处理,包括事件监听器、事件模式(内联与脚本模式)、事件名的分类、事件的执行顺序、键盘和鼠标事件、HTML窗口及表单事件。还讨论了事件委托机制和事件流的概念,以及如何阻止事件冒泡和默认行为。
摘要由CSDN通过智能技术生成

事件的概述

事件是指代一个东西的操作被另一个东西进行监听以后的一个过程(事件),这个过程可以完成对应的操作(处理函数)。事件监听器是一个标准的观察者模式(observe) 也被称为发布、订阅者模式。

示例

点击按钮触发一个操作改变按钮的颜色

事件名:点击

执行对象:按钮

处理对象:js引擎

处理函数:改变按钮颜色

事件的模式

内联模式(嵌入到标签中的)

脚本模式(分离于标签的)

<!-- 内联模式相当于直接帮你调用代码 以浏览器本身来直接执行的 window来帮你执行的 -->
<!--在里面直接嵌入代码-->
<button onclick="alert('你好')">点击弹窗</button>
<!--在里面调用函数 以执行代码的形式执行的-->
<button onclick="handlerClick()">点击弹窗</button>
<button class="btn">脚本模式匿名函数</button>
<button class="btn">脚本模式具名函数</button>
<script>
function handlerClick() {
alert('hello')
console.log(this)//指向window
}
//脚本模式相当于把对应的onclick当成一个属性 也就是把元素element当成一个对象
var btn = document.querySelector('.btn') //类型为对象
console.log(typeof btn) //object 对象可以定义属性
// btn['onclick'] = function(){
// console.log('hello world')
// console.log(this)
// }
btn.onclick = function(){
console.log('hello world')
console.log(this)
}
//具名函数
document.querySelectorAll('.btn')[1].onclick = sayHello
function sayHello(){
alert('hello')
}
</script>

内联模式和脚本模式的区别

  • 内联模式相当于属性赋值  里面的代码是window对象帮你执行,而对应的脚本模式里面的this执行当前的调用元素
  • 脚本模式看不见调用函数 内联模式是直接可以看到执行的函数名

事件名的分类

事件的构成

触发的对象.on+事件名=处理函数

鼠标事件(mouse)

  • 点击事件click
  • 双击事件dblclick
  • 鼠标按下 mousedown
  • 鼠标弹起 mouseup
  • 鼠标移入mouseenter
  • 鼠标移出mouseleave
  • 鼠标移入mouseover
  • 鼠标移出mouseout
  • 鼠标右键 contextmenu
  • 鼠标移动 mousemove
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name=
"
viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
注意事项
执行顺序 mousedown --- mouseup --- click
}
</style>
</head>
<body>
<div>
<button>按钮</button>
</div>
<script>
var div = document.querySelector('div')
//点击事件
div.onclick = function () {
console.log('点击事件')
}
//双击会触发俩次点击
div.ondblclick = function () {
console.log('双击')
}
//按下
div.onmousedown = function () {
console.log('按下')
}
//弹起
div.onmouseup = function () {
console.log('弹起')
}
//先按下 -- 再弹起 -- 再点击
// 并不会向下执行 冒泡 从下到上 (从里到外) 捕获 从上到下(从外到里)
div.onmouseenter = function () {
console.log('移入 enter')
}
div.onmouseleave = function () {
console.log('移出 leave')
}
//向下执行 冒泡
div.onmouseover = function () {
console.log('移入 over')
}
div.onmouseout = function () {
console.log('移出 out')
}
div.oncontextmenu = function(){
console.log('鼠标右键')
}
//鼠标移动 (动画之类的)
div.onmousemove = function(){
console.log('鼠标移动')
}
//在移动端 没有点击 只有触发 touch
</script>
</body>
</html>

注意事项:

执行顺序:先执行mousedown 再执行mouseup 再执行click

mouseenter/mouseleave及mouseover/mouseout的区别,前者不会发生事件冒泡 (也就是子元素不会触发)后者会发生事件冒泡(子元素会触发)

键盘事件

按下 keydown

弹起  keyup

非功能键  keypress(功能不会执行)

window.onkeydown = function(){
console.log('按下')
}
window.onkeyup = function(){
console.log('弹起')
}
window.onkeypress = function(){
console.log('非功能键按下')
}

非功能键触发的过程:keydown   keypress   keyup 

HTML事件

window窗口相关事件

  • load        窗口加载的时候触发的
  • unload        窗口卸载的时候触发的
  • close        窗口关闭的时候触发的
  • beforeunload        在卸载之前触发的
  • beforeprint       打印之前触发的
  • error         窗口出错的时候触发的
  • resize        重新设置大小
  • reset        重新设置位置
  • scroll        滚动栏滚动
  • hashchange         值变化
  • popstate  history的state发生变化
  • ....      
window.onload = function(){
console.log('窗口加载的时候触发的')
}
window.onunload = function(){
console.log('窗口卸载的时候触发的')
}
window.onclose = function(){
console.log('窗口关闭的时候触发的')
}
//页面关闭之前
window.onbeforeunload = function(){
console.log('在卸载之前触发的')
}
window.onbeforeprint = function(){
console.log('打印之前触发的')
}
window.onerror = function(){
console.log('窗口出错的时候触发的')
}
window.onresize = function(){
console.log('窗口可操作空间大小发生变化的时候触发的')
}
window.onreset = function(){
console.log('窗口重新设置位置的时候触发的')
}
window.onscroll = function(){
console.log('窗口滚动栏发生变化的时候触发的')
}
window.onhashchange = function(){
console.log('hash值发生变化的时候触发的')
}
window.onpopstate = function(){
console.log('history中的state发生变化的时候触发的')
}

表单相关事件

  • input 输入
  • change value值发生变化
  • focus  获取焦点
  • blur 失去焦点
  • select  内容被选择
  • submit  提交
  • reset 重置
  • ...
//输入事件
inp.oninput = function () {
console.log('表单输入')
}
//必须先失去焦点
inp.onchange = function () {
console.log('值变化')
}
//value改变事件
select.onchange = function () {
console.log('value发生变化')
}
//获取焦点事件
inp.onfocus = function () {
console.log('获取焦点')
}
//失去焦点事件
inp.onblur = function () {
console.log('失去焦点')
}
//选中内容触发的事件
inp.onselect = function () {
console.log('内容被选中触发')
}
//form表单的事件 reset submit
document.forms[0].onsubmit = function(){
console.log('提交')
}
document.forms[0].onreset = function(){
console.log('重置')
}

event

概述

event是一个事件源对象,他包含了事件触发过程的内容,以及对应的元素的内容。他会默认传入给对应的事件的处理函数。

处理函数的arguments

var btn = document.querySelector('button')
btn.onclick = function (e) { //这个参数e就相当于接收的第一个实参
console.log(arguments)
console.log(arguments.length) //1 当前的这个处理函数内容只有一个参数 这个参数是一个
event对象
//pointerEvent对象 这个对象就是一个事件源对象
console.log(arguments[0]) //传入的第一个实参
// 这个地方的e就相当于是arguments[0]
console.log(e)
console.log(e == arguments[0])
//这个接收的event对象是存在兼容问题 所以为了防止兼容问题的产生 我们一般会在里面先写对应的
兼容
e = e || window.event //兼容写法
}
//从上述可以得到对应的处理函数会被默认传递一个参数这个参数就是对应的事件源对象
//所以我们就可以直接用对应的形参接收实参的方法 通过形参e来接收这个对应的实参event
  • 对应的处理函数的arguments会传递一个参数 而这个参数就是对应的事件源对象
  • 这个事件源对象一般使用形参e来表示 一般的兼容写法为 e = e || window.event

event对象里面的相关属性

  • type 触发事件的类型 *
  • target 触发的目标元素 *
  • currentTarget 当前加事件的元素 *
  • button 鼠标点击的按钮
  • screenX screenY 获取当前鼠标在屏幕上的位置
  • pageX pageY 获取当前鼠标在页面上的位置(包含滚动栏位置)
  • clientX clientY 获取当前鼠标在可视区的位置 (不包含滚动栏)
  • offsetX offsetY 获取当前鼠标在目标元素上的位置
  • altKey shiftKey ctrlKey 是否按下对应的功能键 *
  • cancelBubble 取消冒泡 *
  • returnValue 是否执行对应的默认行为 *
  • bubbles 是否冒泡 *

//对应的属性
console.log(e.type) //获取对应的事件名
console.log(e.target) //获取对应的事件的目标元素 你当前执行事件的目标元素
console.log('按钮触发了')
console.log(e.currentTarget) //获取当前加事件的元素
//位置 鼠标点击的坐标
//获取鼠标点击位置的页面坐标 包含滚动栏
console.log(e.pageX)
console.log(e.pageY)
//获取鼠标在页面可视区的位置 不包含滚动栏的
console.log(e.clientX)
console.log(e.clientY)
//获取鼠标在对应的盒子里面的位置 也就是在按钮中的位置
console.log(e.offsetX)
console.log(e.offsetY)
//获取鼠标处在屏幕的位置 不包含滚动栏
console.log(e.screenX)
console.log(e.screenY) //加上导航栏的位置
//ctrlKey shiftKey altKey 是否按照ctrl键 是否按照shift键 是否按着alt键
console.log(e.ctrlKey,e.shiftKey,e.altKey)
//按那么键 0 1 2
console.log(e.button)
//取消冒泡
console.log(e.cancelBubble) //默认值为false
//返回的value值 返回true就可以走 返回false就不能走 走不走对应的默认行为
console.log(e.returnValue) //默认值为true
//是否冒泡
console.log(e.bubbles)

 键盘相关的event属性

  • key 按下的键 返回键的字符串
  • keyCode 按下键的ascii码 (返回大写的ascii码 如果是keypress事件那么返回是对应的)
  • charCode 字符键按下才有的 ascii 如果是给keypress事件那么对应的keyCode和charCode是一致的
//属于键盘事件源的属性
console.log(e.key) //按下的键 返回键的字符串
console.log(e.keyCode) //按下键的ascii码 返回大写的ascii码
console.log(e.charCode) //字符键按下才有的 ascii 如果是给keypress事件那么对应的keyCode
和charCode是一致的

事件委托机制(事件代理)

概述

事件委托机制就是将自己的事件委托给对应的父元素去添加,在内部利用对应的target来指向执行元素的特性来进行相关的操作。

示例

给所有的li添加一个点击事件点击添加背景颜色

//原本的做法 获取所有的li 遍历添加点击事件
//利用事件委托 将对应的点击事件委托给对应的父元素 ul
var ul = document.querySelector('ul')
ul.onmouseover = function(e){
e = e || window.event
//利用e.target来获取对应的执行的元素
if(e.target.tagName = 'LI'){
//排他思想
//将所有的li颜色变为白色
for(var li of ul.children){
li.style.backgroundColor = '#fff'
}
//给他添加背景颜色
e.target.style.backgroundColor = '#f00'
}
}
//应用场景 如果有多个共同的元素要添加一个事件 那么可以委托给他的父元素来进行代理
//注意事项 如果需要使用事件委托 那么对应的事件一定要支持事件冒泡(利用事件冒泡来完成操作的)

注意事项

  • 如果需要使用事件委托 那么对应的事件一定要支持事件冒泡(利用事件冒泡来完成操作的)
  • 如移入移出功能需要添加事件委托 那么必须使用mouseover/mouseout 不能使用mouseenter/mouseleave

事件流的传播流程

事件流的传播有三个阶段

  • 捕获阶段
  • 目标阶段
  • 冒泡阶段

 捕获阶段:从最外层找到对应的事件执行的元素

window——document——body——div——button

目标阶段:找到这个button 执行button对应的事件

冒泡阶段:逐层向上冒泡执行对应的事件

事件流的俩种模式

冒泡模式(从里到外 逐层执行对应的事件)

冒泡模式是常用的模式 ,他现在默认设计的就是冒泡模式。

<div onclick="alert(1)">
<button onclick="alert(2)"></button>
</div>
<script>
document.body.onclick = function () {
alert(3)
}
document.onclick = function () {
alert(4)
}
window.onclick = function () {
alert(5)
}
</script>
  • 以上的这个示例 会从button开始不断向上执行 直到window停止 所以对应的执行结果为 2 1 3 4 5

如果我们不想触发对应的外层的事件 只是想触发本身的事件 那么我们就需要禁止事件冒泡了

禁止事件冒泡的处理

stopPropagation(event对象的方法  对于低版本ie浏览器不支持)

document.querySelector('button').onclick = function(e){
//事件源对象
e = e || window.event
//禁止事件冒泡的方法
e.stopPropagation()
alert(2)
}

cancelBubble(event对象的属性)

//cancelBubble 取消冒泡 默认为false
e.cancelBubble = true

兼容写法

e.stopPropagation?e.stopPropagation():e.cancelBubble = true

捕获模式(从外到里 逐层执行对应的事件)

捕获模式他是火狐提出来的模式,ie对应的6、7、8 不支持。现在的模式一般很少使用捕获模式。

默认行为

元素标签有默认行为(a标签会默认跳转页面 form标签里面submit默认提交(刷新)),对应的事件也有其默认行为(contextmenu会出现对应的菜单栏等)。

e.defaultPrevented 检测当前是否禁止默认行为

console.log(e.defaultPrevented) //是否阻止默认行为 只读 默认为false

禁止默认行为

preventDefault(event对象的方法)

e.preventDefault() //preventDefault阻止默认行为

returnValue (event对象的属性)

e.returnValue = false //兼容ie的

兼容写法

e.preventDefault?e.preventDefault():e.returnValue = false

return false

//对应的右键点击
window.oncontextmenu = function(e){
console.log('右键点击了')
// e.preventDefault?e.preventDefault():e.returnValue=false
return false //一定要放在最后
}

事件监听器

eventListener他是一个标准的观察者模式,他是通过对应的监听器来监听事件的触发和执行。

主要有俩个方法

  • addEventListener添加事件监听器
  • removeEventListener 移除事件监听器

addEventListener

传入对应的事件名及处理函数以及对应的是否冒泡

//获取按钮
var btn = document.querySelector('button')
//添加事件监听器 传入 事件名 处理函数 是否捕获(默认的事件模式 冒泡 false 捕获 true)
// btn.addEventListener('click',function(){
// console.log('按钮点击了')
// })//指定为冒泡模式
// btn.addEventListener('click',function(){
// console.log('按钮点击了1')
// },true)//指定为捕获模式 先执行
// btn.addEventListener('click',function(){
// console.log('按钮点击了2')
// })
//addEventListener 他可以给一个事件添加多个处理函数
//一个事件 有一个处理函数的数组
//事件监听器中的事件名 支持自定义
// btn.addEventListener('dblclick',function(){
// console.log('双击')
// })
//直接使用onclick 进行赋值的操作他会被覆盖也就是说他只有一个处理函数 后写会覆盖先写的 (属性赋
值操作)
// document.querySelector('div').onclick = function(){
// console.log('div被点击了')
// }
btn.addEventListener('click',handler,false)//指定为冒泡模式

注意事项

  • addEventListener 可以在一个事件中传入多个处理函数 (一个事件对应一个处理函数数组)
  • EventListenter 支持自定义事件名
  • 属性事件赋值不支持多个处理函数 (因为会被覆盖)

removeEventListener

移除对应的添加的事件监听器,传入事件名、处理函数、是否冒泡 每个都必须和添加的事件监听器一致不然不能被移除

btn.addEventListener('click',handler,false)//指定为冒泡模式
// 要移除的事件名 要移除的处理函数(也要一致 如果是匿名函数那么就不能被移除 对象比对的是地址) 模
式也要一致
btn.removeEventListener('click',handler,false)
function handler(){
console.log('按钮点击了')
}

注意事项

  • 如果添加事件监听器的时候传入处理函数为匿名处理函数 那么不能被移除(对象比对的是地址)

拖拽

拖拽原理

  • 给对应的需要拖拽的元素添加鼠标按下事件
  • 在按下事件内添加给区间的元素对应的鼠标移动事件
  • 在按下事件内给document添加对应的鼠标弹起事件 在弹起事件中释放移动事件及释放弹起事件 

基础拖拽 

思路

  • 获取拖拽的元素
  • 给拖拽元素添加鼠标按下事件 并记录按下的坐标(在对应的盒子里的坐标)
  • 在按下事件内给区间元素添加鼠标移动事件 并记录每次移动的坐标
  • 在区间元素的鼠标移动事件中 设置对应的拖拽元素的坐标(移动的坐标 = 当前的坐标 - 鼠标点击位置的坐标 + 'px')
  • 在按下事件内在document中添加鼠标弹起事件 并释放之前的移动事件及自身的弹起事件
<div></div>
<script>
var box = document.querySelector('div')
box.onmousedown = function(e){
e = e || window.event
//记录在而盒子上的坐标
var x = e.offsetX
var y = e.offsetY
//在document中移动
document.onmousemove = function(e){
e = e || window.event
//获取页面上的坐标
var currentX = e.pageX
var currentY = e.pageY
//移动的坐标 = 当前的坐标 - 鼠标点击位置的坐标 + 'px'
box.style.left = currentX - x + 'px'
box.style.top = currentY - y + 'px'
}
document.onmouseup = function(){
document.onmousemove = null
document.onmouseup = null
}
}
</script>

区间拖拽

offset家族(属于元素对象element对象)

  • offsetParent 偏移的父元素 (从里到外找有定位的父元素 没有的话就是body)
  • offsetLeft 左偏移量 (不包含偏移的父元素本身的margin 包含偏移的父元素本身padding border)
  • offsetTop 上偏移量
  • offsetHeight 偏移元素的高度 (包含padding及border 不包含margin)
  • offsetWidth 偏移元素的宽度

思路

  • 获取拖拽的元素
  • 给拖拽元素添加鼠标按下事件 并记录按下的坐标(在对应的盒子里的坐标)
  • 在按下事件内给区间元素添加鼠标移动事件 并记录每次移动的坐标
  • 在区间元素的鼠标移动事件中 获取对应的区间元素的位置 及 能够移动的距离 (区间元素的宽/高度 - 自身的宽/高度)
  • 设置移动元素处在区间元素的位置移动位置在父元素的坐标 = 页面的位置 - 父元素离页面的位置- 鼠标点击的位置
  • 对应坐标位置进行区间判断 小于0的时候值应该设置为0 大于能够移动的距离设为最大的距离
  • 在按下事件内在document中添加鼠标弹起事件 并释放之前的移动事件及自身的弹起事件
<div>
<button>
移动的按钮
</button>
</div>
<script>
var box = document.querySelector('div')
var button = document.querySelector('button')
button.onmousedown = function(e){
e = e || window.event
//记录在而盒子上的坐标
var x = e.offsetX
var y = e.offsetY
//在box中移动
box.onmousemove = function(e){
e = e || window.event
//获取区间元素的位置
var bx = this.offsetLeft
var by = this.offsetTop
//获取能够移动的最大距离
var maxX = this.offsetWidth - button.offsetWidth
var maxY = this.offsetHeight - button.offsetHeight
//移动位置在父元素的坐标 = 页面的位置 - 父元素离页面的位置 - 鼠标点击的位置
var targetX = e.pageX - bx - x
var targetY = e.pageY - by - y
//进行区间判断
if(targetX < 0){
targetX = 0
}
if(targetY < 0){
targetY = 0
}
if(targetX > maxX){
targetX = maxX
}
if(targetY > maxY){
targetY = maxY
}
button.style.left = targetX + 'px'
button.style.top = targetY + 'px'
}
document.onmouseup = function(){
box.onmousemove = document.onmouseup = null
}
}
</script>

封装一个方法找盒子到页面的距离

function getBoxToPageDistance(element){
var distance = {
x:0,
y:0
} //距离对象
while(element.offsetParent){ //找到body就停止
distance.x += element.offsetLeft
distance.y += element.offsetTop
element = element.offsetParent
}
return distance
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值