IFE:第10天 事件

事件是您在编程时系统内发生的动作或者发生的事情——系统会在事件出现的时候触发某种信号并且会提供一个自动加载某种动作,列举一些可能发生的事件。

  • 用户在某个元素上点击鼠标或悬停光标。
  • 用户在键盘中按下某个按键。
  • 用户调整浏览器的大小或者关闭浏览器窗口。
  • 一个网页停止加载。
  • 提交表单。
  • 播放、暂停、关闭视频。
  • 发生错误。

1.事件处理器

可以为每一个事件绑定一个事件处理器(事件监听器),用以事件被激发时做出的回应,有三种事件处理器。

1.1 事件处理器属性(DOM0级)
var btn = document.querySelector('button');
btn.onclick = function(event){alert('Hello world');};

该函数在定义时,可以传入一个 event 形式的参数,该方式的问题在于一次只能绑定一个。

除了onclick还有一些常见的事件处理器属性

事件处理器属性备注
btn.onfocus当前元素获得键盘焦点时会触发focus事件
btn.onblur当一个元素失去焦点时会触发blur事件
btn.ondblclick当前元素上双击鼠标左键会触发dblclick事件
window.onkeypress当用户在键盘上按下任意键时,应当会触发 keypress 事件
window.onkeydown当用户按下键盘上的按键时会触发keydown事件
window.onkeyup在当前元素上释放键盘按键时会触发keyup事件
btn.onmouseover当鼠标移动到一个元素上时,会在这个元素上触发mouseover事件
btn.onmouseout当鼠标离开一个元素时,会在这个元素上触发mouseout事件
1.2 行内事件处理器 - 请勿使用
<button onclick="alert('Hello World');">Press me</button>

我们应该避免使用这种方式。因为它会使标记数量变大,而可读性却较差。 内容/结构 和 行为之间没有很好的分离,使得在处理bug时非常困难。

1.3 addEventListener()(DOM2级)
var btn = document.querySelector('button');
btn.addEventListener('click', function(){alert('Hello world');}, false);
addEventListener()参数
参数名传入参数
type表示监听事件类型的字符串。
listener实现了Event接口的对象或者函数
options 可选一个指定有关 listener属性的可选参数对象
useCapture 可选Boolean,默认为false,在事件冒泡阶段调用事件处理程序,反之为捕获
addEventListener()返回值

undefined

您也可以给同一个监听器注册多个处理器,下面这种方式不能实现这一点:

myElement.onclick = functionA;
myElement.onclick = functionB;

第二行会覆盖第一行,但是下面这种方式就会正常工作了:

myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);

当元素被点击时两个函数都会工作

注意:通过addEventListener()添加的事件处理程序只能用removeEventListener()来移除,并且移除时传入的参数必须与添加时传入的参数一样。

1.4 IE事件处理器

//IE事件处理程序(IE和Opera支持)
//IE用了attachEvent(),detachEvent(),接收两个参数,事件名称和事件处理程序,通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段,所以平时为了兼容更多的浏览器最好将事件添加到事件冒泡阶段,IE8及以前只支持事件冒泡;

例子:

var btn = document.getElementById('btn');
var handlers = function(){
	console.log(this === window);  //true,注意attachEvent()添加的事件处理程序运行在全局作用域中;
};
btn.attachEvent('onclick', handlers);
跨浏览器事件处理程序
//创建的方法是addHandlers(),removeHandlers(),这两个方法属于一个叫EventUtil的对象;但是这个没有考虑到IE中作用域的问题,不过就添加和移除事件还是足够的。
 
var EventUtil = {
   addHandlers: function (element, type, handlers) {
      if (element.addEventListener) {
         element.addEventListener(type, handlers, false);
      } else if (element.attachEvent) {
         element.attachEvent(on + type, handlers);
      } else {
         element['on' + type] = handlers;
      }
   },
   removeHandlers: function (element, type, handlers) {
      if (element.removeEventListener) {
         element.removeEventListener(type, handlers, false);
      } else if (element.detachEvent) {
         element.detachEvent(on + type, handlers);
      } else {
         element['on' + type] = null;
      }
   }
};

例子:

var btn = document.getElementById('btn');
var handlers = function() {
   console.log('123')
};
EventUtil.addHandlers(btn, 'click', handlers);
EventUtil.removeHandlers(btn, 'click', handlers);

在同一个对象上注册事件,并不一定按照注册顺序执行,冒泡或捕获模式会影响其被触发的顺序

2.事件冒泡及捕获

当一个事件发生在具有父元素的元素上,现代浏览器运行两个不同的阶段——捕获阶段和冒泡阶段。

2.1捕获阶段
  • 浏览器检查元素的最外层祖先<html>,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后,它移动到<html>中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。
2.2冒泡阶段
  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达<html>元素。
2.3用stopPropagation()修复问题

当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)。

3.事件对象 event

eventevt或简单的e。 这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息,比如:

function bgChange(e) {
  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}  
btn.addEventListener('click', bgChange);

事件对象 etarget属性始终是事件刚刚发生的元素的引用。

IE中的事件对象

在这里插入图片描述

跨浏览器的事件对象

虽然DOM和IE中对象不同,但是两者event中的全部信息和方法都是类似的只是实现方式不同,可以用前面提到过的EventUtil对象来求同存异。

var EventUtil = {
    addHandler: function (element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent(on + type, handler);
        } else {
            element['on' + type] = handler;
        }
    },

    getEvent: function (event) {
        return event ? event : window.event;

    },

    getTarget: function (event) {
        return event.target || event.srcElement;
    },

    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },

    stopPropagation: function (event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },

    removeHandler: function (element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent(on + type, handler);
        } else {
            element['on' + type] = null
        }
    }
};

4.事件委托

4.1 问题初现

给100个按钮绑定事件,传统的做法就是:通过DOM操作获取每一个按钮元素分别绑定事件处理函数。

但在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间。

而每一个函数都是一个对象,所以都会占用内存,内存占用的越多性能毋庸置疑的会变得越差。

4.2 解决方案——事件委托

事件委托就是利用事件冒泡,即:利用冒泡机制将一类事件触发尽可能高的委托给其父节点或祖先节点来触发事件处理函数,这样只需要定义一个函数,访问一次DOM对象,减少了内存的占用以及访问DOM元素的时间,降低了性能的消耗。

例子
点击某一个 Li 标签时,将 Li 的背景色显示在 P 标签内,并将 P 标签中的文字颜色设置成 Li 的背景色,下面是html

<ul class="palette">
	<li style="background-color:crimson"></li>
	<li style="background-color:bisque"></li>
	<li style="background-color:blueviolet"></li>
	<li style="background-color:coral"></li>
	<li style="background-color:chartreuse"></li>
	<li style="background-color:darkolivegreen"></li>
	<li style="background-color:cyan"></li>
	<li style="background-color:#194738"></li>
</ul>

<p class="color-picker"></p>

实现方法

const list = document.querySelector(".palette");
list.onclick = function(e) {
    e = e || window.event;
    const t = e.target || e.srcElement;
    const p = document.getElementsByClassName('color-picker')[0];

    if (t.nodeName.toLowerCase() === 'li') {
        p.innerHTML = t.style.backgroundColor;
        p.style.color = t.style.backgroundColor;
    }
}

适合事件委托的事件有:click,mousedown,mouseup,keydown,keyup,keypress。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值