一、先记个小知识点。cssText

cssText 本质:设置 HTML 元素的 style 属性值。

用法:document.getElementById("d1").style.cssText= "color:red; font-size:13px;";

cssText 返回值:在某些浏览器中(比如 Chrome),你给他赋什么值,它就返回什么值。在 IE 中则比较痛苦,它会格式化输出、会把属性大写、会改变属性顺序、会去掉最后一个分号,比如:

cssText的使用优势:样式一多,代码就很多;而且通过JS来覆写对象的样式是比较典型的一种销毁原样式并重建的过程,这种销毁和重建,都会增加浏览器的开销。语法为:obj.style.cssText=”样式”;这样就可以尽量避免页面reflow,提高页面性能。

但是,这样会有一个问题,会把原有的cssText清掉,比如原来的style中有’display:none;’,那么执行完上面的JS后,display就被删掉了。为了解决这个问题,可以采用cssText累加的方法:

Element.style.cssText += ‘width:100px;height:100px;top:100px;left:100px;’

注意:上面cssText累加的方法在IE中是无效的。解决办法是,可以在前面添加一个分号来解决这个问题:

Element.style.cssText += ‘;width:100px;height:100px;top:100px;left:100px;’

补充:如果前面有样式表文件写着 div {text-decoration:underline; },这个会被覆盖吗?不会!因为它不是直接作用于 HTML元素的 style 属性。

二、JS的事件处理机制

1、事件流:指从页面中接收事件的顺序,有冒泡流和捕获流。

2、DOM2级事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的是事件捕获,然后是实际的目标接收道事件,最后是冒泡阶段,可以在这个阶段对事件做出响应。

分析:实际的(text)元素在捕获阶段不会接收到事件,意味着在捕获阶段,事件从document到<body>再到<div>后就停止了。下一个阶段是“处于目标阶段”,于是事件在(text)上发生,并在事件处理中被看成是冒泡阶段的一部分。最后,冒泡阶段发生,事件又传播回文档。

3、事件处理程序

诸如click,load,mouseover都是事件的名字,而响应某个事件的函数就是事件处理程序(事件侦听器)。事件处理程序的名字以on开头,比如onclick.onmouseover等。

(1)HTML事件处理程序:某个元素支持的每种事件,都可以用一个相应事件处理程序同名的HTML特性来决定。

<input type="button" value="click" οnclick="alert('clicked')"/>
<input type="button" value="click" οnclick="alert(event.type)"/>

第二动态创建的函数中会有一个局部变量event,也就是事件对象。通过event变量,可以直接访问事件对象。

另外,这个动态创建的函数扩展作用域的方式如下:使用with

在这个函数内部,可以像访问局部变量一样访问document及该元素本身的成员。

function(){with(documnet){with(this){/元素属性值}}
}

(2)DOM0级事件处理程序

基于DOM0的事件,对于同一个dom节点而言,只能注册一个,后边注册的 同种事件 会覆盖之前注册的。利用这个原理我们可以解除事件,btn5.onclick=null;其中this就是绑定事件的那个元素;

这里添加的事件处理程序是在其依附的元素的作用域中运行。

DOM0级对每个事件只支持一个事件处理程序。

(3)DOM2级事件处理程序

DOM2支持同一dom元素注册多个同种事件,事件发生的顺序按照添加的顺序依次触发(IE是相反的)。DOM2事件通过addEventListener和removeEventListener管理。
DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener(eventName,handlers,boolean)和removeEventListener(),两个方法都一样接收三个参数,要处理的事件名,第二个是事件处理程序函数,第三个值为布尔值。
布尔值是true,表示在捕获阶段调用事件处理程序。false时表示在事件冒泡阶段调用事件处理程序,一般建议在冒泡阶段使用,特殊情况才在捕获阶段;
注意:通过addEventListener()添加的事件处理程序只能用removeEventListener()来移除,并且移除时传入的参数必须与添加时传入的参数一样;通过addEventListener()添加的匿名函数将无法移除。(js高程P351-P352)
使用DOM2级事件处理程序可以添加多个事件处理程序:
var btn2 = document.getElementById('btn2');
var handlers = function () {
   console.log(this.id);
 };
btn2.addEventListener('click',handlers,false);
btn2.addEventListener("click",function(){alert("hello")},false);btn2.removeEventListener('click',handlers.false);

这里为按钮添加了两个事件处理程序,他们会按照添加他们的顺序触发。

(4)IE事件处理程序

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

 var btn3 = document.getElementById('btn3');var handlers2=function(){console.log(this===window);//true,注意attachEvent()添加的事件处理程序运行在全局作用域中;};btn3.attachEvent('onclick',handlers2);

分析:attachEvent()的第一个参数是“onclick”DOM则是“click”

重点:在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行。因此this等于window。

attachEvent()也可以为同一元素添加两个不同的事件处理程序。只是执行事件时以相反的顺序被触发。

(5)跨浏览器事件处理程序

为了以跨浏览器的方式处理事件,有两个方法,addHandler(),它的职责是视情况分别使用DOM0和DOM2或者IE方法来添加或删除事件。这个方法属于一个名叫EventUtil的对象,可以处理浏览器差异。这个方法接收三个参数。要操作的元素、事件名称、和事件处理程序函数。对应的方法是removeHandler()函数,它的职责是移除事件处理程序。默认采用DOM0级方法。

4 事件对象

触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含了所有与事件有关的信息,比如导致事件的元素target,事件的类型,及其他特定的相关信息。例如鼠标操作导致的事件对象中会包含鼠标的位置,单双击等,而键盘操作导致的事件对象会包含按下的键等信息;

事件被触发时,会默认给事件处理程序传入一个参数e , 表示事件对象;通过e,我们可以获得其中包含的与事件有关的信息;
只有在事件处理程序执行期间,event对象才会存在,一旦事件处理程序执行完毕,event对象就会被销毁;

(1)DOM中的事件对象

兼容DOM的浏览器会自动将一个事件对象event传递给事件处理程序。

在通过HTML特性指定事件处理函数时,变量event中保存着event对象。event对象包含与创建它的特定事件的有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。

currentTarget 只读 事件处理程序当前正在处理事件的那个元素
datail 只读 与事件相关的细节
eventPhase 只读 调用事件处理程序的阶段1 捕获阶段 2  处于目标 3 冒泡阶段
target 只读 事件的目标
type 只读 被触发的事件的类型

在事件处理程序内部,对象this始终等于currentTarget的值,target包含事件的实际目标。

ps:关于事件对象中的this,target,currentTarget,看个例子:(注:event.target不支持IE浏览器,应该用event.srcElement;还有 IE中通过attachment添加的事件是运行在全局作用域中的,this===window。

preventDefault() 阻止事件的默认行为,只有cancelabel属性的值设为true时,才可以使用preventDefalut.
event.stopPropagation()可以阻止事件的传播.,取消进一步的事件冒泡或者捕获

(2)IE中的事件对象

要访问IE的event对象有几种不同的方式,取决于指定事件处理程序的方法。

比如使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在,因此可以通过window.event来访问event对象。

var btn=document.getElementById("myBtn");
btn.οnclick=function(){var event=window.event;alert(event.type);
}

输出结果是click.

如果是使用attachEvent()来添加事件处理程序,那么会有一个对象作为参数传入事件处理程序函数中。
var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(event){alert(event.type);
});

输出结果是click.

IE中event对象同样包含与创建它的事件相关的方法和属性。其中很多属性和方法都有对应的或者相关的DOM属性和方法。这些属性和方法会因为事类型的不同而不同。

srcElement 只读 事件的目标(与DOM中target属性相同)
type 只读 被触发的事件的类型
cancelBubble 读/写 默认值为false,设置为true可以取消事件冒泡(与DOM中stopPropagation()一样)
returnValue 读/写 默认为true,设置为false,就可以阻止默认行为。(与DOM中的preventDefault()一样)
将returnValue设置为false,就可以阻止默认行为。
cancelBubble属性值为true,可以取消事件冒泡。

(3)跨浏览器的事件对象

虽然DOM和IE中对象不同,但基于二者之间的相似性依旧可以拿出跨浏览器的方案来。

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

var EventUtil(){addHandler:function(element,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;}},
   removeHandler:function(element,type,handler){//省略代码
},
stopPropagation:function(event){if(event.stopPropagation){
      event.preventDefault();}else{
event.cancelBubble=true; }
}
};

以上代码为EventUtil 添加了4个方法;getEvent(),返回event对象的引用。其它方法类似。

5 事件委托

因为冒泡机制,比如既然点击子元素,也会触发父元素的点击事件,那我们完全可以将子元素的事件要做的事写到父元素的事件里,也就是将子元素的事件处理程序写到父元素的事件处理程序中,这就是事件委托;利用事件委托,只指定一个事件处理程序,就可以管理某一个类型的所有事件;

通俗来说:事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

示例1:

<ul id="ul1"><li>111</li><li>222</li><li>333</li><li>444</li>
</ul>

实现点击li出现123.

传统方法:

window.onload = function(){var oUl = document.getElementById("ul1");var aLi = oUl.getElementsByTagName('li');for(var i=0;i<aLi.length;i++){aLi[i].onclick = function(){alert(123);}}
}

使用事件委托:

window.onload = function(){var oUl = document.getElementById("ul1");oUl.onclick = function(){alert(123);}
}

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发???

示例2:

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement。

window.onload = function(){var oUl = document.getElementById("ul1");oUl.onclick = function(ev){var ev = ev || window.event;var target = ev.target || ev.srcElement;if(target.nodeName.toLowerCase() == 'li'){alert(123);alert(target.innerHTML);}}
}

这样,只有点击li才会触发事件。

示例3

对比下列两段代码实现:

window.onload = function(){var oBtn = document.getElementById("btn");var oUl = document.getElementById("ul1");var aLi = oUl.getElementsByTagName('li');var num = 4;//鼠标移入变红,移出变白for(var i=0; i<aLi.length;i++){aLi[i].onmouseover = function(){this.style.background = 'red';};aLi[i].onmouseout = function(){this.style.background = '#fff';}}//添加新节点oBtn.onclick = function(){num++;var oLi = document.createElement('li');oLi.innerHTML = 111*num;oUl.appendChild(oLi);};}

注意:这里添加的新节点并不会有事件处理程序。

window.onload = function(){var oBtn = document.getElementById("btn");var oUl = document.getElementById("ul1");var aLi = oUl.getElementsByTagName('li');var num = 4;//事件委托,添加的子元素也有事件oUl.onmouseover = function(ev){var ev = ev || window.event;var target = ev.target || ev.srcElement;if(target.nodeName.toLowerCase() == 'li'){target.style.background = "red";}};oUl.onmouseout = function(ev){var ev = ev || window.event;var target = ev.target || ev.srcElement;if(target.nodeName.toLowerCase() == 'li'){target.style.background = "#fff";}};//添加新节点oBtn.onclick = function(){num++;var oLi = document.createElement('li');oLi.innerHTML = 111*num;oUl.appendChild(oLi);};}

用事件委托的方式,新添加的子元素是带有事件效果的,我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。

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

传统实现:

 var list = document.querySelectorAll("li");for (var i = 0, len = list.length; i < len; i++) {list[i].onclick = function(e) {var t = e.target;var c = t.style.backgroundColor;var p = document.getElementsByClassName("color-picker")[0];p.innerHTML = c;p.style.color = c;}}

运用事件委托:

   var ulist=document.getElementsByClassName("palette")[0];ulist.οnclick=function(ev){var ev = ev || window.event;var target = ev.target || ev.srcElement;if (target.nodeName.toLowerCase() === 'li') {var c = target.style.backgroundColor;var p = document.getElementsByClassName("color-picker")[0];p.innerHTML = c;p.style.color = c;}}
注意:ul只有一个,要用索引,[0],如果不写,无法实现。
总结一下js委托相关的:
  • 因为把事件绑定到了父节点上,因此省了绑定事件。就算后面新增的子节点也有了相关事件,删除部分子节点不用去销毁对应节点上绑定的事件
  • 父节点是通过event.target来找对应的子节点的。(事件处理程序中的this值始终等于currentTarget的值,指向的是绑定到的那个元素)

JS的事件处理机制以及事件代理(事件委托)相关推荐

  1. JavaScript事件代理和委托

    2019独角兽企业重金招聘Python工程师标准>>> 浏览器的事件冒泡 当事件发生后,这个事件就要开始传播.例如我们点击一个按钮时,就会产生一个click事件,但这个按钮本身不能处 ...

  2. 简诉事件代理(事件委托)及其优点

    事件代理 不给每个子节点单独设置事件监听器,而是设置在其父节点上,然后利用冒泡原理设置每个子节点. 优点 1. 减少内存消耗和 dom 操作,提高性能. 在 JavaScript 中,添加到页面上的事 ...

  3. 记录JS event Loop机制及Node v8事件执行机制

    转载于:https://www.cnblogs.com/liujiekun/p/11295536.html

  4. JS 事件代理和事件委托

    目录 事件委托的概念理解 为什么要用事件委托 事件委托的原理: 事件代理(委托)实现 总结: 事件委托的概念理解 为什么叫事件委托?它还有一个名字叫事件代理. JavaScript高级程序设计上讲:事 ...

  5. a标签点击事件_DOM事件机制

    前言 本文主要介绍DOM事件级别.DOM事件模型.事件流.事件代理和Event对象常见的应用,希望对你们有些帮助和启发! 一.DOM事件级别 DOM级别一共可以分为四个级别:DOM0级.DOM1级.D ...

  6. 用例子解释事件模型和事件代理

    事件模型 事件传播模型 在说事件代理之前,先来说一下事件模型. 在浏览器开发的早期,面对事件触发模型的问题,所有的程序员都认为事件触发不应该是直接触发的,而应该在文档中有一个传播的过程,然而事件传播的 ...

  7. 事件链、事件代理、页面的渲染过程、style的操作、防抖与节流【DOM(四)】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目录 文章目录 1.事件链(冒泡目标捕获) (1)事件链原理 (2)阻止冒泡和默认事件 2.事件代理(面试笔试题重点) 3. ...

  8. 使用事件代理实现vue的手风琴组件

    1.为什么要使用事件代理? 在项目中要做一个手风琴组件,需求是页面created事件中请求数据,以显示在列表中,加载数据时显示"正在加载",没有数据了就显示"没有更多数据 ...

  9. Event事件-1:addEventListener事件监听 / 事件冒泡事件捕获 / 事件委托 / preventDefault 阻止默认行为 / cancelBubble、stopPropa...

    addEventListener 事件监听器 target.addEventListener(type, listener[, options|useCapture])     添加事件监听 参数: ...

最新文章

  1. tensorflow 使用CPU而不使用GPU的问题解决
  2. 存clob为空的值_oracle clob 存储空间
  3. Python | raise...from... 是个什么操作?
  4. 洛谷 - P5192 Zoj3229 Shoot the Bullet|东方文花帖|【模板】有源汇上下界最大流(有源汇有上下界的最大流)
  5. python高级玩法_python pandas to_excel 高级玩法
  6. 仅完成部分的readprocessmemory或write_王者荣耀:三种李小龙获取方式!无需完成任务、28号即可兑换...
  7. Java讲课笔记08:数组
  8. lvs的调度算法有几种_LVS支持哪些调度算法?
  9. 排序sort,统计wc
  10. LeetCode 303. 区域和检索 - 数组不可变(动态规划)
  11. struts2.2跟jstl怎么整合
  12. 5.Docker技术入门与实战 --- 访问 Docker 仓库
  13. 智能优化算法:黏菌优化算法 - 附代码
  14. 定制性MES系统软件
  15. 思科交换机接口配置trunk_思科交换机虚拟串口配置VLAN Trunk的步骤
  16. java中产生0-100之间的随机整数
  17. 【ASE入门学习】ASE入门系列六——塞尔达扰动火焰
  18. QJsonObject 和 QByteArray 互转
  19. 国足0-2日本 出线仅存理论可能
  20. ISE中显示IP核的图形化界面

热门文章

  1. Java8 流式递归树形菜单
  2. 怎么选择一个好的网站建设公司?需要注意些什么?
  3. Excel使用VBA批量插入Object
  4. 【电源专题】分流监控器(电流感测放大器)
  5. IOS9.3详细使用体验:Night Shift功能实用,备忘录加密保护信息安全
  6. 中专计算机应用专业介绍,计算机应用技术专业介绍_中职中专网
  7. 【AI每日播报】意念控制特斯拉 AI看漫画
  8. 前端登录页如何做记住密码
  9. mysql数据库de_MySQL 数据库常用命令
  10. php ksort 底层实现,PHP ksort()函数与示例