JavaScript事件高级操作
文章目录
1:注册事件
给元素添加事件(注册事件/绑定事件)
注册事件有两种: 传统方式和监听注册方式
传统方式
- onclick 利用on开头的事件
- btn.οnclick=function(){}
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面注册的处理函数
监听注册方式
-
w3c标准 推荐方式
-
addEventListener()是一个方法
addEventListener(‘事件类型’,事件函数)
事件类型是字符串,必须加引号 ,不带on
-
IE9之前的ie浏览器不支持此方法,可使用attachEvent()代替
-
同一个元素同一个事件可以注册多个监听器
-
按注册的顺序依次执行
事件监听
eventTaget.addEventListener(type,事件处理程序[,useCapture])
将指定的监听器注册到eventTaget(事件目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
type 事件类型 字符串 比如click ,mouseover 注意不要on
listener 事件处理程序 事件发生时,会调用该监听函数
useCapture 可选参数,是一个布尔值默认是false, 后面学习
兼容性解决方案
function addEventListenerFn(element, eventName, fn) {
// 判断当前浏览器是否支持addEventListener方法
if (element.addEventListener) {
element.addEventListener(eventName, fn)
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn)
} else {
// 相当于element.onclick = fn
element['on' + eventName] = fn
}
}
2 删除事件
-
传统
eventTarget.onclick = null
-
监听注册方式
eventTarget.removeEventListener(type,listener[,useCapture]) eventTarget.datachEvent(eventNameWithOn,callback)
兼容处理
function removeEventListenerFn(element, eventName, fn) {
// 判断当前浏览器是否支持
if (element.removeEventListener) {
element.removeEventListener(eventName, fn)
} else if ((element, detachEvent)) {
element.detachEvent('on' + eventName, fn)
} else {
element['on' + eventName] = null
}
}
DOM事件流
html中的标签都是相互嵌套的,我们可以想象成一个盒子装一个盒子,document是最外面的大盒子,当你点击一个div时,你也点击了div的父元素,甚至整个页面
事件流就是描述从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程就是DOM事件流
事件冒泡:IE最早提出,事件开始由具体的元素接收,然后逐级向上传播到DOM最顶级节点的过程
事件捕获:网景最早提出,由DOM最顶级节点开始,然后逐级向下传播到具体的元素接收的过程
w3c采用折中的方式,制定了统一的标准, ----先捕获再冒泡
事件流会经历3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
注意:
js代码中只能执行捕获或者冒泡的其中 一个阶段
onclick和attachEvent只能得到冒泡阶段
addEventListener(type,listener[,useCapture])第三个参数如果是true表示再事件捕获阶段调用事件处理函数,如果是false(默认是false)表示再事件冒泡阶段调用事件处理函数,
实际开发中,很少使用事件捕获,更关注事件冒泡
有些事件是没有冒泡的,onblur. onfocus,onmouseenter,onmouseleave
事件对象
事件对象:事件发生后,跟事件相关的一些列信息数据的集合都被放到这个对象里面,这个对象就是事件对象
使用
事件触发发生就会产生事件对象,并且系统会以形参的形式传递给事件处理函数
事件处理函数中声明一个形参来接收事件对象
事件对象的属性和方法
e.target 返回触发事件的对象 标准
e.srcElement 返回触发事件的对象 非标准 ie6~8
e.type 返回事件的类型 比如 click mouseover 不带on
e.preventDefault() 阻止默认行为,不让链接跳转
e.stopPropagation() 阻止事件冒泡
事件委托
事件委托: 把事情委托给别人,代为处理
事件委托也称为事件代理,在jQuery里面称为事件委派
不给子元素注册事件,给父元素注册事件,把处理代码在父元素的事件中执行
原理:
给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素
作用
1:只操作了一次dom,提高了程序的性能
2:动态新创建的子元素,也拥有事件
鼠标事件对象
event 事件对象是事件相关的一系列信息的集合
禁用右键菜单案例,禁止选中文字案例
<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>
</head>
<body>
我是一段不愿意分享的文字
<script>
// contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu', function (e) {
e.preventDefault()
})
// selectstart 禁止选中文字
document.addEventListener('selectstart', function (e) {
e.preventDefault()
})
</script>
</body>
</html>
鼠标事件对象
e.clientX 返回鼠标相对于浏览器窗口可视区域的X坐标
e.clientY 返回鼠标相对于浏览器窗口可视区域的Y坐标
e.pageX 返回鼠标相对于文档页面的X坐标 ie9+支持
e.pageY 返回鼠标相对于文档页面的Y坐标 ie9+支持
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标
跟随鼠标的天使案例
<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>
img {
position: absolute;
top: 2px;
}
</style>
</head>
<body>
<img src="./ts.png" width="50" alt="" />
<script>
/*
1:鼠标不断的移动,使用鼠标移动事件 mousemove
2:在页面中移动,给document注册事件
3:图片要移动距离 而且不占位置,使用绝对定位
核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,
把这个x和y坐标作为图片的top和left 就可以移动图片
*/
var pic = document.querySelector('img')
document.addEventListener('mousemove', function (e) {
// mousemove 只要我们鼠标移动1px 就会触发这个事件
// console.log(1)
// 每次鼠标移动,我们都会获得最新的鼠标坐标,
// 把这个x和y坐标作为图片的top和left 就可以移动图片
var x = e.pageX
var y = e.pageY
pic.style.left = x + 'px'
pic.style.top = y + 'px'
})
</script>
</body>
</html>
键盘事件
onkeyup 键盘按键松开时触发
onkeydown 键盘按键按下时触发
onkeypress 键盘按键按下时触发 但是它不识别功能键 比如 ctrl shift 箭头等
键盘事件对象
keyCode 返回该键的ASCII值
注意:
- onkeydown 和onkeyup不区分字母大小写,onkeypress区分字母大小写
- 实际开发中,更多的使用keydown和keyup能识别所有的键
- keypress不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值
元素偏移量offset
offset
offset就是偏移量,使用offset的相关属性可以动态的得到该元素的位置(偏移),大小等.
offset系列属性
element.offsetTop 返回元素相对带有定位父元素上方的偏移 或者父元素没有定位 以body为准
element.offsetLeft 返回元素相对带有定位父元素左边的偏移
element.offsetWidth 返回自身包括padding 边框 内容区的宽度,返回的值不带单位
element.offsetHeight 返回自身包括padding 边框 内容区的高度,返回的值不带单位
offset和style的区别
offset
- offset可以得到任意表中的样式值
- offset获取的数值是没有单位的
- offsetWidth包含padding+border+width
- offsetWidth等属性是只读属性,只可以获取不可以赋值
- 所有我们要获取元素大小位置,用offset 更合适
style
- style之可以得到行内样式中的样式值
- style.width获得的是带有单位的字符串
- style.width获取不包含padding和border的值
- style.width是可读写属性,可以获取也可以赋值
- 所有我们要给元素更改值,需要用style改变
元素可视区client系列
client
client就是客户端,使用client的相关属性获取可视区的相关信息,通过client的相关属性可以动态的得到该元素的边框大小,元素大小
client相关属性
element.clientTop 返回元素上边框的大小
element.clientLeft 返回元素左边框的大小
element.clientWidth 返回自身包括padding 内容区的宽度 不含边框
element.clientHeight 返回自身包括padding 内容区的高度 不含边框
元素滚动scroll系列
scroll
scroll就是滚动,使用scroll的属性可以动态的得到该元素的大小,滚动距离等
scroll相关属性
element.scrollTop 返回被卷去的上侧距离 返回的数值不带单位
element.scrollLeft 返回被卷去的左侧距离 返回的数值不带单位
element.scrollWidth 返回自身实际的宽度 不含边框 返回数值不带单位
element.scrollHeight 返回自身实际的高度 不含边框 返回数值不带单位
三大系列总结
element.offsetWidth 返回自身包括padding,边框,内容区的宽度,返回值不带单位
element.clientWidth 返回自身包括padding,内容区的宽度,不含边框,返回值不带单位
element.scrollWidth 返回自身实际的宽度,不含边框,返回值不带单位
offset 用于获取元素位置 offsetLeft offsetTop
client 用户获取元素大小 clientWidth clientHeight
scroll 获取滚动距离 scrollTop scrollLeft
页面滚动的距离 window.pageYOffset
拖拽模态框案例
思路
1点击弹出层,会弹出模态框,并且显示灰色半透明的遮罩层
2:点击关闭按钮,,关闭模态框 并且关闭灰色半透明遮罩层
3:鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动
4:鼠标松开,可以停止拖动模态框移动在页面中拖拽的原理: 鼠标按下并且移动,之后松开鼠标 鼠标按下mousedown 鼠标移动 mousemove 鼠标松开mouseup 拖拽:鼠标移动的过程中,获取最新的值赋值给模态框的left和top值,模态框就可以跟着鼠标移动 鼠标按下触发的事件源 是最上面一行, id="title" 鼠标的坐标-鼠标在盒子内 的坐标 就是模态框真正的位置 鼠标按下 得到鼠标在盒子的坐标 鼠标移动 设置模态框的位置 鼠标的坐标-鼠标在盒子内 的坐标 移动事件要写在按下事件里面 鼠标松开 停止拖拽,让移动事件解除
代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title></title>
<style>
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
ul,
li,
ol,
dl,
dt,
dd,
div,
p,
span,
h1,
h2,
h3,
h4,
h5,
h6,
a {
padding: 0px;
margin: 0px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, 0.3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="login-header">
<a id="link" href="javascript:;">点击,弹出登录框</a>
</div>
<div id="login" class="login">
<div id="title" class="login-title">
登录会员
<span
><a id="closeBtn" href="javascript:void(0);" class="close-login"
>关闭</a
></span
>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input
type="text"
placeholder="请输入用户名"
name="info[username]"
id="username"
class="list-input"
/>
</div>
<div class="login-input">
<label>登录密码:</label>
<input
type="password"
placeholder="请输入登录密码"
name="info[password]"
id="password"
class="list-input"
/>
</div>
</div>
<div id="loginBtn" class="login-button">
<a href="javascript:void(0);" id="login-button-submit">登录会员</a>
</div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
<script>
/*
1点击弹出层,会弹出模态框,并且显示灰色半透明的遮罩层
2:点击关闭按钮,,关闭模态框 并且关闭灰色半透明遮罩层
3:鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动
4:鼠标松开,可以停止拖动模态框移动
在页面中拖拽的原理:
鼠标按下并且移动,之后松开鼠标
鼠标按下mousedown 鼠标移动 mousemove 鼠标松开mouseup
拖拽:鼠标移动的过程中,获取最新的值赋值给模态框的left和top值,模态框就可以跟着鼠标移动
鼠标按下触发的事件源 是最上面一行, id="title"
鼠标的坐标-鼠标在盒子内 的坐标 就是模态框真正的位置
鼠标按下 得到鼠标在盒子的坐标
鼠标移动 设置模态框的位置 鼠标的坐标-鼠标在盒子内 的坐标 移动事件要写在按下事件里面
鼠标松开 停止拖拽,让移动事件解除
*/
var loginEle = document.querySelector('#login')
var mask = document.querySelector('.login-bg')
var linkEle = document.querySelector('#link')
var closeBtn = document.querySelector('#closeBtn')
var title = document.querySelector('#title')
// 1点击弹出层,会弹出模态框,并且显示灰色半透明的遮罩层
linkEle.addEventListener('click', function () {
loginEle.style.display = 'block'
mask.style.display = 'block'
})
// 2:点击关闭按钮,,关闭模态框 并且关闭灰色半透明遮罩层
closeBtn.addEventListener('click', function () {
loginEle.style.display = 'none'
mask.style.display = 'none'
})
// 1) 鼠标按下 获取鼠标在盒子内的坐标
title.addEventListener('mousedown', function (e) {
var x = e.pageX - loginEle.offsetLeft
var y = e.pageY - loginEle.offsetTop
// 2)鼠标移动, 鼠标的坐标-鼠标在盒子内 的坐标 就是模态框的left和top的值
document.addEventListener('mousemove', move)
function move(e) {
loginEle.style.left = e.pageX - x + 'px'
loginEle.style.top = e.pageY - y + 'px'
}
// 鼠标松开,移除移动事件
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move)
})
})
</script>
</body>
</html>