一、事件复习
事件三要素: 事件源 + 事件名称 + 事件处理程序
事件源:谁触发这个事件(按钮btn)
事件名称:触发了什么事件(点击click事件)
事件处理程序:事件触发后要执行的代码(函数形式)--- 可以是有名字的函数,不加小括号
1.事件语法:标签.on事件类型 = 函数
二.事件类型
1.鼠标事件
(1)click:左键单击
(2)contextmenu:右键单击
(3)dblclick:双击
(4)mousedown:左键按下
(5)mouseup:左键弹起
(6)mouseover:鼠标放上去(在子元素上也会触发)
(7)mouseout:鼠标离开
(8)mouseenter:鼠标放上去
(9)mouseleave:鼠标离开
(10)mousemove:鼠标移动事件
(11)mousewheel:鼠标滚轮事件
2.浏览器事件
(1)load:加载
(2)scroll:滚动
(3)resize:大小改变
3.键盘事件
(1)keydown:按下
(2)keyup:弹起
(3)keypress:敲打
4.表单事件
(1)submit:提交表单 - 给form标签绑定,点击表单域中提交按钮的时候触发,在跳转之前触发
(2)focus:获取焦点
(3)blur:失去焦点
(4)change:内容改变并失去焦点 - 下拉框选项/单选框状态/复选框状态改变
(5)input:input的value值改变 - 改变了文本框的内容就会触发的事件
使用说明:input事件在低版本的IE中不兼容,使用onpropertychange
代替。
<body>
<form action="">
<input type="radio" name="gender" value="男">男
<input type="radio" name="gender" value="女">女
<br>
<input type="checkbox" name="hobby" value="唱歌">唱歌
<input type="checkbox" name="hobby" value="跳舞">跳舞
<input type="checkbox" name="hobby" value="摇头">摇头
<input type="checkbox" name="hobby" value="rap">rap
<br>
<input type="text" name="username">
</form>
</body>
<script>
// change
var radioInput = document.querySelector('[name="gender"]')
// 当用户点击了这个单选框并让他的状态发生了改变触发事件
radioInput.onchange = function () {
console.log(radioInput.checked);
console.log('改变了');
}
// // 点击选中,再点击取消
var flag = false
radioInput.onclick = function () {
// 获取当前input的选中状态
// console.dir(radioInput) // 第一种写法获取当前input的选中状态
// console.log(radioInput.checked); // 第二种写法获取当前input的选中状态
// 如果他的状态是true
// if (!radioInput.checked) {
// radioInput.checked = true
// }
if (flag) {
// 设置选中状态
radioInput.checked = false
flag = false
} else {
radioInput.checked = true
flag = true
}
}
var checkboxInput = document.querySelector('[name="hobby"]')
checkboxInput.onchange = function () {
console.log(checkboxInput.checked);
console.log('改变了');
}
// input - 百度就是这个写法
var textInput = document.querySelector('[name="username"]')
textInput.oninput = function () {
console.log(textInput.value);
}
</script>
三、事件流
1.定义
每个事件发生的时候,都会有一个触发并执行的过程,也就是事件的传播过程,我们称之为事件流。简单来说,事件从开始触发到执行结束所经历的整个过程.
2.事件流包含3个阶段
(1)捕获阶段:由外向内找目标元素的过程
(2)目标阶段:开始执行目标元素事件函数
(3)冒泡阶段:由内向外离开目标元素的过程
事件捕获阶段:事件开始由顶层元素触发,然后逐级向下传播,直到目标元素,依次执行其身上绑定的事件。
事件目标阶段(处理阶段):触发当前自身的事件。
事件冒泡阶段:事件由目标元素先接收,然后逐级向上传播,达到最顶层元素,依次执行其身上绑定的事件。
3.注意
(1)目标元素的事件在目标阶段执行,其他事件会在冒泡阶段执行
(2)目标元素的祖宗标签如果有同类型的事件,会在冒泡阶段执行
四、事件侦听器
1.定义:另外一种事件绑定方式 - 事件侦听器
2.语法:标签.addEventListener(事件类型, 函数代码, 当前事件是否在别人的捕获阶段执行,默认是false)
// 事件流
var small = document.querySelector('.small')
var middle = document.querySelector('.middle')
var big = document.querySelector('.big')
small.addEventListener('click', function () {
console.log('小');
})
middle.addEventListener('click', function () {
console.log('中');
}, true)
big.addEventListener('click', function () {
console.log('大');
})
// 同类型事件不能绑定多次
small.onclick = function(){
console.log('111');
}
small.onclick = function(){
console.log('222');
} // 覆盖第一个111
// 使用事件侦听器 - 同类型事件可以绑定多次
small.addEventListener('click',function(){
console.log('111');
})
small.addEventListener('click',function(){
console.log('222')
})
三、事件解绑
1.定义
(1)什么叫解绑:把事件删除掉
(2)为什么解绑:有的事件执行一次后就不需要执行,但是事件会一直保存在内存中,浪费内存
(3)怎么解绑:
标签.on类型 = 函数 ---------- 解绑方式:标签.on类型 = null
事件侦听器 --------------------- 解绑方式:标签.removeEventListener(事件类型, 绑定的那个函数)
2.事件绑定标签.on类型=函数
,事件绑定后,存储的函数不会自动丢失,会一直在内存中保存下去。
<body>
<button>按钮</button>
<p style="background-color: #f00;">解绑</p>
</body>
<script>
var btn = document.querySelector('button')
btn.onclick = function () {
console.log(666);
}
console.dir(btn)
</script>
// 事件为什么能触发?因为我们给标签的 onclick属性赋值了一个函数
// 为什么触发一次后还能触发?因为触发一次后 onclick属性的值还是一个函数
var btn = document.querySelector('button')
console.dir(btn)
// 事件绑定之前为什么不能触发?因为绑定之前 onclick属性 值是null
3.解绑 - 事件解绑
btn.onclick这种绑定方式 - 解绑:btn.onclick = null
var btn = document.querySelector('button')
btn.onclick = function () {
console.log(666);
btn.onclick = null // 解绑,还原到被绑定之前
}
console.dir(btn)
4.事件侦听器绑定
var btn = document.querySelector('button')
btn.addEventListener('click', function () {
console.log(666);
})
5.事件侦听器解绑
事件侦听器绑定的事件,解绑需要使用特殊的方式:
标签.removeEventListener(事件类型, 绑定的那个函数)
var a = function(){
console.log(666);
}
var b = function () {
console.log(666);
}
console.log(a === b); /* false - 不相等 - 因为把一段函数赋值给变量a,function是引用
类型,把函数值存到堆里,把地址存到栈里,b同样也是,完全没关系,所以不相等 */
var a = function(){
console.log(666);
}
var btn = document.querySelector('button')
document.querySelector('p').onclick = function () {
// 解绑btn的事件
btn.removeEventListener('click', a)
}
四、事件对象
1.引入
document.querySelector('button').onclick = fn
function fn(a){
conso.log(666)
}
/* 如上这样一个事件,想给这个函数传第一个实参,让形参a接收,怎么传? - 没找到函数调用的小
括号,但肯定调用了,但是在哪里调用的呢?因为事件绑定后,事件函数是由浏览器监听到用户触发
事件后,去调用这个函数执行的 */
// 浏览器在调用这个函数的时候,会给函数传递一个实参
// 这个实参是一个对象 - 事件对象:其中记录了很多跟当前事件相关的信息,比如鼠标的位置
2.定义
浏览器为事件提供了一个对象,用来记录事件的各种具体信息,例如,鼠标点击的位置、鼠标按键的信息、键盘的键码。。。这就是事件对象。浏览器在调用事件函数的时候,给函数传递了一个实参 --- 对象
(1)第一种写法:针对IE浏览器,基本都兼容
<body>
<button id="btn">按钮</button>
</body>
<script type="text/javascript">
btn.onclick = function () {
console.log(window.event);
}
</script>
(2)第二种写法:针对W3C标准浏览器,在IE低版本浏览器中还不兼容
btn.onclick=function(e){
console.log(e);
}
(3)第三种写法:兼容所有浏览器的写法
btn.onclick = function(e){
var ev = e || window.event
console.log(ev);
}
如果是行内绑定的事件,就将事件对象当做参数传进来即可。且必须是event。
<button onclcik="fn(event)">
按钮
</button>
<script>
function fn(e){
console.log(e);
}
</script>
五、事件对象的作用
储存了当前事件相关的所有信息
怎么获取对象?
事件函数通过形参接收或window.event
1.获取事件类型
事件对象.type ---- 看是什么事件
var btn = document.querySelector('button')
btn.onclick = function(e) {
btn.onmouseover = function(e) {
console.log(e.type); // 事件类型 - e.type
}
2.获取鼠标按键码
事件对象.button
(1)左键 - 0
(2)滚轮 - 1
(3)右键 - 2
<button id="btn">按钮</button>
<script type="text/javascript">
btn.onmousedown = function(e){
var ev = e || window.event;
var code = ev.button;
if(code == 0){
console.log("您点击的是左键");
}else if(code == 1){
console.log("您点击的滚轮");
}else if(code == 2){
console.log("您点击的是右键");
}else{
console.log("不知道你点击的是什么");
}
}
</script>
3.获取键盘按键码
单个 - 事件对象.keyCode
(1)回车键:13
(2)空格键:32
(3)上下左右:38 40 37 39
(4)数字:数字对应的阿斯克码
(5)字母:大写字母的阿斯克码
<body>
<button id="btn">按钮</button>
</body>
document.onkeyup = function(e) {
var code = e.keyCode // 按键码 - e.keyCode
console.log(code);
var word = String.fromCharCode(code).toLowerCase() // 判断是否按的是c键
if(word === 'c') {
console.log('按的c');
}
</script>
组合键 - 布尔值
(1)事件对象.ctrlKey:alt 键和别的键一起按下得到 true,否则得到 false
(2)事件对象.shiftKey:shift 键和别的键一起按下得到 true,否则得到 false
(3)事件对象.altKey:ctrl 键和别的键一起按下得到 true,否则得到 false
(4)事件对象.metaKey:win键和别的键一起按下返回true,否则返回false
document.onkeyup = function(e) {
var code = e.keyCode
console.log(e.ctrlKey);
if(word === 'c' && e.ctrlKey) {
console.log('按住了ctrl+c'); // 判断是否按住了ctrl+c
}
}
4.获取鼠标位置
相对标签 - 从元素内部开始计算的坐标
(1)事件对象.offsetX
(2)事件对象.offsetY
相对浏览器窗口
使用说明:不管页面滚动到哪里,都是根据窗口来计算坐标。(不会随着滚动条的滚动而
发生改变)
(1)事件对象.clientX
(2)事件对象.clientY
相对整个网页
使用说明:会随着滚动条的滚动而加大,横向坐标也是一样的
(1)事件对象.pagex
(2)事件对象.pageY
<body>
x轴:<span>0</span>
<br>
y轴:<span>0</span>
</body>
<script>
document.onmousemove = function(e) {
var x = e.pageX
var y = e.pageY
document.querySelectorAll('span')[0].innerText = x
document.querySelectorAll('span')[1].innerText = y
}
</script>
5.阻止事件冒泡 - 任选其一,现在都兼容
在事件对象中,有一个方法用来阻止事件冒泡,这个方法叫做stopPropagation。
(1)事件对象.stopPropagation()
(2)事件对象.cancelBubble = true
(3)兼容写法
if(e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
<style>
.big{
width: 300px;
height: 300px;
background-color: #f00;
}
.middle{
width: 200px;
height: 200px;
background-color: #0f0;
}
.small{
width: 100px;
height: 100px;
background-color: #00f;
}
</style>
<body>
<div class="big">
<div class="middle">
<div class="small"></div>
</div>
</div>
</body>
<script>
var big = document.querySelector('.big')
var small = document.querySelector('.small')
var middle = document.querySelector('.middle')
big.onclick = function() {
console.log('大');
}
middle.onclick = function() {
console.log('中');
}
small.onclick = function(e) {
var e = e || window.event
//第一种 - 阻止事件冒泡 - e.stopPropagation()
// e.stopPropagation()
//第二种 - 低版本ie中 - e.cancelBubble = true
// e.cancelBubble = true
//第三种 - 兼容写法
if(e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
console.log('小');
}
</script>
6.阻止默认行为
有的标签天生就有行为,用不着绑定事件,比如<a>
(1)事件对象.preventDefault() - 低版本ie中不兼容
(2)事件对象.returnValue = false - 在ie中可以使用
(3)在事件的底部加 return false ----- 通常会在事件函数的最下面写一行代码,就能阻止
默认行为
(4)有链接的标签,将连接改成: javasccript:; ---- 如:<a href="javascript:;">百度</a>
<body>
<a href="http://baidu.com">百度</a>
</body>
<script>
// 有的标签天生就有行为,用不着绑定事件,比如<a>
document.querySelector('a').onclick = function(e) {
console.log('点击了a标签。不跳了');
// console.log(b); /* 此处打开b会报错,事件对象阻止默认行为就怕报错,如果报
错,后续代码就 执行不了 */
e.preventDefault() // 第二种
}
7.获取精准的目标元素
(1)事件对象.target
(2)事件委托
概念:子委托父处理他的事件,事件委托也叫事件代理(看站谁的角度),使用事件委托技术能避免对每个子节点添加事件监听,相反把事件监听委托给父元素即可,这样可提高绑定事件的性能。
原理:事件冒泡
好处:(1)减少绑定次数,提高性能
(2)动态添加的子标签也能有事件
缺点:(1)li标签比较多的时候,性能特别差,毕竟使用for循环相当于绑定了多
次
(2)当动态给li添加元素的时候,新元素没有事件绑定
注意:事件委托底层就是通过事件冒泡来完成的,先触发父元素的事件,在通过事件对象的target属性找到具体的目标元素,进而在处理目标元素要执行的业务逻辑。