Loading

js-事件基础

@


① 事件概述

事件是可以被 JavaScript 侦测到的行为(触发--- 响应机制)。

网页中的每个元素都可以产生某些可以触发 JavaScript 的事件, 例如, 我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。




② 事件三要素

1. 事件源

触发事件的节点对象


2. 事件类型

常见鼠标事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
ondblclick 鼠标双击触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onmouseenter 鼠标经过触发
onmouseleave 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发
contextmenu 鼠标右键菜单触发
selectstart 鼠标开始选中时触发

contextmenu

contextmenu主要控制应该何时显示上下文菜单,主要用于开发者取消默认的上下文菜单

document.addEventListener('contextmenu', function(e) {
	e.preventDefault();//禁止事件默认行为
})

selectstart

主要用于禁止鼠标选中( selectstart 开始选中)

document.addEventListener('selectstart', function(e) {
	e.preventDefault();//禁止事件默认行为
})

两种鼠标经过离开事件的区别

//eg
 var father = document.querySelector('.father');
 var son = document.querySelector('.son');

 father.addEventListener('mouseover', function() {
      console.log('over');
 })
father.addEventListener('mouseout',function(){
    console.log('out');
})

 father.addEventListener('mouseenter', function() {
      console.log('enter');
 })
father.addEventListener('mouseleave',function(){
    console.log('leave');
})
  • onmouseover \ onmouseout

    它们都会冒泡,当子节点触发事件时,事件流流到父节点并执行父节点绑定的监听器。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBMtMFvL-1630226220918)(WebAPIs.assets/a.gif)]

  • onmouseenter \ onmouseleave

    它们不会冒泡,子节点触发事件不会执行父节点的监听器

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JvKqbJM8-1630226220923)(WebAPIs.assets/b.gif)]

移动端click事件的延时问题

移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。

解决方案:

  1. 禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。

    <meta name="viewport" content="user-scalable=no">
    
  2. 利用touch事件自己封装这个事件解决 300ms 延迟。

    原理:

    • 当我们手指触摸屏幕,记录当前触摸时间
    • 当我们手指离开屏幕, 用离开的时间减去触摸的时间
    • 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击
    //封装tap,解决click 300ms 延时
    function tap (obj, callback) {
    	var isMove = false;
    	var startTime = 0; // 记录触摸时候的时间变量
    	obj.addEventListener('touchstart', function (e) {
    		startTime = Date.now(); // 记录触摸时间
    	});
    	obj.addEventListener('touchmove', function (e) {
    	isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击
    	});
    	obj.addEventListener('touchend', function (e) {
    		if (!isMove && (Date.now() - startTime) < 150) { // 如果手指触摸和离开时间小于150ms 算点击
    		callback && callback(); // 执行回调函数
    		}
    		isMove = false; // 取反 重置
    		startTime = 0;
    	});
    }
    //调用
    tap(div, function(){ // 执行代码 });
    
  3. fastclick 插件解决 300ms 延迟。 使用延时

    GitHub官网地址

    使用步骤:

    • 引入js文件

    • 在相关js文件中引入如下语句

      if ('addEventListener' in document) {
      	document.addEventListener('DOMContentLoaded', function() {
      		FastClick.attach(document.body);
      	}, false);
      }
      
      //此时,click事件就不会有延时问题
      element.addEventListener('click', function() {
                  alert(11);
      })
      

ondblclick双击事件默认选中问题

比如双击一个元素节点(事件源)里的文本时,会默认把文本选中

解决方案:在监听函数里写上如下代码即可解决文本默认选中的特性

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

常见的键盘事件

键盘事件 触发条件
onkeyup 某个键盘被松开时触发
onkeydown 某个键盘被按下时触发
onkeypress 某个键盘按键被按下时并弹起时触发

注意:

  • onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头, shift 等。

滚动事件onscroll

滚动条在滚动时会触发 onscroll 事件。


触屏事件

触屏事件概述

移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android和 IOS 都有。

touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。

常见触屏事件

触屏touch事件 说明
touchstart 一个DOM元素上出现触点时触发
touchmove 触点在一个DOM元素上滑动时触发
touchend 触点在一个DOM元素上移开时触发

touchmove 触点移动事件默认也会触发页面滚动事件,若页面宽高超出屏幕,随着触点的移动页面也会移动


过度事件

transitionend

transitionend - Web API 接口参考 | MDN (mozilla.org)


change事件

change - Web API 接口参考 | MDN (mozilla.org)


表单事件

form.submit

MDN

oninput

GlobalEventHandlers.oninput - Web API 接口参考 | MDN (mozilla.org)


3. 监听器(事件处理程序 )

事件触发后要执行的代码(函数形式),事件处理函数

<body>
    <button id="btn">唐伯虎</button>
    <script>
        // 点击一个按钮,弹出对话框
        // 1. 事件是有三部分组成  事件源  事件类型  事件处理程序   我们也称为事件三要素
        //(1) 事件源 事件被触发的对象   谁  按钮
        var btn = document.getElementById('btn');
        //(2) 事件类型  如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
        //(3) 事件处理程序  通过一个函数赋值的方式 完成
        btn.onclick = function() {
            alert('点秋香');
        }
    </script>
</body>



③ 执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采取函数赋值形式)
<!-- 案例:点击按钮弹出警示框 -->
<html>
	<button id="btn"> hello </button>
</html>
<script>
 	//1
    var btn = document.getElementById('btn');
    //2
    //btn.onclick;
    //3
    btn.onclick = function() {
        alert('world');
    }
</script>


④ 注册事件(绑定事件)

给元素添加事件,称为注册事件或者绑定事件。

1. 传统注册方式

<button onclick=" alert('hi~')"></button>
btn.onclick = function() {
    //...
}

同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数,这是传统注册事件的唯一性

兼容性较好


2. 方法监听注册方式

addEventListener()

  • 语法
eventTarget.addEventListener(type, listener, useCapture)
  • 作用:该方法将指定的监听器注册到 eventTarget( 目标对象)上,当该对象触发指定的事件时, 就会执行事件处理函数。

  • 参数 说明
    type 事件类型字符串, 比如 click 、 mouseover , 注意这里不要带 on
    listener 事件处理函数, 事件发生时,会调用该监听函数
    useCapture 可选参数, 是一个布尔值,默认是 false;表示事件流
  • 特点

    • 同一个元素同一个事件可以注册多个监听器(事件处理函数)按注册顺序依次执行。
    • IE9 之前的 IE 不支持此方法

attachEvent ()

  • 语法

    eventTarget.attachEvent(eventNameWithOn, callback)
    
  • 作用:该方法方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时, 指定的回调函数就会被执行。

  • 参数 说明
    eventNameWithOn 事件类型字符串,比如 onclick 、 onmouseover ,这里要带 on
    callback 事件处理函数,当目标触发事件时回调函数被调用
  • 特点

    • 同一个元素同一个事件可以注册多个监听器按注册顺序依次执行。
    • IE8 及早期版本支持

3.) 注册事件兼容性解决方案

兼容性处理的原则: 首先照顾大多数浏览器,再处理特殊浏览器

/*
参数说明
element:元素对象
eventName:事件类型
fn:监听器
*/
function addEventListener(element, eventName, fn) {
	// 判断当前浏览器是否支持 addEventListener 方法,若不支持返回 undefined
	if (element.addEventListener) {
		element.addEventListener(eventName, fn); // 第三个参数 默认是false
	} else if (element.attachEvent) {
		element.attachEvent('on' + eventName, fn);
	} else {
		// 相当于 element.onclick = fn;
		element['on' + eventName] = fn;
	}
}    


⑤ 删除事件(解绑事件)

1. 传统注册方式解绑

//eventTarget:绑定事件的元素对象
eventTarget.onclick = null;

2. 方法监听注册方式解绑

//解除addEventListener绑定的事件
eventTarget.removeEventListener(type, listener, useCapture);
//解除attachEvent绑定的事件
eventTarget.detachEvent(eventNameWithOn, callback);

3. 删除事件兼容性解决方案

function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
	if (element.removeEventListener) {
		element.removeEventListener(eventName, fn); // 第三个参数 默认是false
	} else if (element.detachEvent) {
		element.detachEvent('on' + eventName, fn);
	} else {
		element['on' + eventName] = null;
	}
}	


⑥ DOM事件流

事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播, 这个传播过程即 DOM 事件流。

DOM 事件流分为3个阶段:

  1. 捕获阶段
  2. 当前目标阶段
  3. 冒泡阶段

比如:我们给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。

请添加图片描述

  • 事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
  • 事件捕获: 网景最早提出, 由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。

注意

  1. JS 代码中事件的注册只能在捕获或者冒泡其中的一个阶段,但浏览器全过程事件流依然执行。
  2. onclickattachEvent 只能得到冒泡阶段。
  3. addEventListener(type, listener, useCapture)第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
  4. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
  5. 有些事件是没有冒泡的,比如 onblur、 onfocus、 onmouseenter、 onmouseleave


⑦ 事件对象

1. 简介

eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event){})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt

event 对象代表事件的状态, 比如键盘按键的状态、鼠标的位置、鼠标按钮的状态

事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象



2. 事件对象的使用

eventTarget.onclick = function(event) {
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
}
eventTarget.addEventListener('click', function(event) {
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
})

这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
当我们注册事件时, event 对象就会根据事件类型被系统自动创建, 并依次传递给事件监听器(事件处理函数) 。



3. 事件对象的兼容性方案

事件对象本身的获取存在兼容问题:

  1. 标准浏览器中是浏览器给方法传递的参数, 只需要定义形参 e 就可以获取到。
  2. 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话, 需要到 window.event 中获取查找。

解决:

e = e || window.event;  


4. 事件对象的常见属性和方法

事件对象属性方法 说明
e.target 返回触发事件的对象(标准)
e.srcElement 返回触发事件的对象(非标准,ie6~8使用)
e.type 返回事件类型,比如 click(不带on), mouseover
e.returnValue 该属性阻止默认事件(默认行为,非标准,ie6~8使用,比如不让链接跳转)
e.preventDefault() 该方法阻止默认事件(默认行为,标准)
e.stopPropagation() 阻止冒泡(标准)
e.cancelBubble 该属性阻止冒泡(非标准,ie6~8使用)

this 、 e.currentTarget \ e.target 、e.srcElement 的区别

  • this、e.currentTarget 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)

    • 兼容性问题:

      this兼容性较好,推荐使用

      e.currentTarget 针对IE9之前

  • e.target 、e.srcElement 是事件触发的元素。

    • 兼容性问题:

      e.target 高版本浏览器支持

      e.srcElement 针对IE9之前

    • 解决方案

      e = e || window.event;
      var target = e.target || e.srcElement;
      

阻止默认事件

元素对象默认事件?

阻止默认事件的三种方法

  1. e.preventDefault()

    有兼容性问题,高版本适配

  2. e.returnValue

    有兼容性问题,低版本适配

  3. return false

    没兼容性问题,但其后的语句不会执行

实例

<body>
    <a href="www.baidu.com">百度</a>
</body>
<script>
	var a = document.querySelector('a');
    a.onclick = function(e) {
        //阻止链接默认的跳转事件
        //方式一
        if(e){
           e.preventDefault();
        }else{
           e = window.event;
           e.returnValue;
        }
		//方式二
         //return false;
        
    }
</script>

阻止事件冒泡

  • 标准写法:利用事件对象里面的 stopPropagation()方法

    e.stopPropagation()
    
  • 非标准写法: IE 6-8 利用事件对象 cancelBubble 属性

    e.cancelBubble = true;
    
  • 阻止事件冒泡的兼容性解决方案

    if(e && e.stopPropagation){
    	e.stopPropagation();
    }else{
    	window.event.cancelBubble = true;
    }
    

鼠标事件对象常见属性

鼠标事件的类型很多,但它们的事件对象都是MouseEvent

常见属性

属性 说明
e.clientX 返回鼠标相对于浏览器窗口可视区域的 X 坐标
e.clientY 返回鼠标相对于浏览器窗口可视区域的 Y 坐标
e.pageX 返回鼠标相对于文档页面的 X 坐标 IE9+支持
e.pageY 返回鼠标相对于文档页面的 Y 坐标 IE9+支持
e.screenX 返回鼠标相对于电脑屏幕的 X 坐标
e.screenY 返回鼠标相对于电脑屏幕的 Y 坐标

键盘事件对象常见属性

键盘事件对象 说明
e.keyCode 返回改键的ASCII值
e.key 返回按下的键名
  • key有严重的兼容性问题,不推荐使用
  • keyup 、keydown 事件不区分字母大小写 a 和 A 得到的keyCode值都是65,keypress 事件 区分字母大小写 a 97 和 A 得到的是65

触摸事件对象

TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件对象。这类事件对象用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等。

类型 何时触发
touchstart 触摸元素时触发
touchmove 移动触点时触发
touchend 触点消失时触发

每个触摸事件都会各自有事件对象。

element.addEventListener('touchstart',function() {
    console.log(e);
})

请添加图片描述

常见的触摸事件对象属性:

属性 说明
e.touches 正在触摸屏幕的所有触点的一个列表
e.targetTouches 正在触摸当前DOM元素上的触点的一个列表
e.changedTouches 触点状态发生了改变的列表,从无到有,从有到无变化
e.preventDefault() 该方法阻止默认事件,比如:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动

这三属性都返回一个TouchList对向,记录触点和触点的数量

请添加图片描述

一般都是给元素注册触摸事件,所以重点记住 targetTocuhes

targetTouches['0']//返回第一个触点对象Touch

请添加图片描述

案例:

  var div = document.querySelector('div');
        div.addEventListener('touchstart', function(e) {
            console.log(e.touches);
            console.log(e.targetTouches);
            console.log(e.changedTouches);
        })

        div.addEventListener('touchmove', function(e) {
            console.log(e.touches);
            console.log(e.targetTouches);
            console.log(e.changedTouches);
        })

        div.addEventListener('touchend', function(e) {
            console.log(e.touches);
            console.log(e.targetTouches);
            console.log(e.changedTouches);
        })

上述事件分别以一触点触发一次,输出如下结果

请添加图片描述



5. 事件委托(代理,委派)

<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            alert('hello');
            var list = ul.children;
            for (var i = 0; i < list.length; i++) {
                list[i].style.backgroundColor = '';
            }
            e.target.style.backgroundColor = 'pink';
        })
    </script>
</body>

事件委托也称为事件代理, 在 jQuery 里面称为事件委派。

原理不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点

作用:只操作了一次 DOM ,提高了程序的性能


posted @ 2022-01-26 15:16  Hong•Guo  阅读(78)  评论(0)    收藏  举报