了解javascript中的事件(二)

零、寒暄

这篇博客本该出现在两个月以前,但是种种原因,搁浅了。两个月的时间,改变了许多人也改变了许多事,回头看看自己两个月前写的代码,居然有很多可笑之处,这也算是一种成长吧。实习的几个月里,全身心的投入工作,效率奇高,同时,离开学校的这段日子让我充分感受了这个社会的残酷。好酒需陈酿,来的早不如来的巧,今天跟大家分享下javascript中事件的下半部分。

如需查看本文的上一篇,请猛击了解javascript中的事件(一),注:后文如无特殊说明,提到的参考之前的博客,也是指这篇文章。

本文主要谈一下几个部分:

(1)事件的分类

(2)事件代理

(3)以及事件代理思想的用处

一、事件的分类

上一篇博客中说到了事件的处理程序有三种类型:分别是HTML级事件处理程序、DOM0级事件处理程序、DOM2级事件处理程序。事件的处理当然与事件的来源分不开,现在我们说下事件有哪些类型。

随着HMTL5的推广以及移动设备的普及,浏览器所支持的事件类型和事件数量在不断的增长。简单的来说,事件大致可以分为以下几类:

(1)依托于输入设备而产生的事件

比如键盘事件和鼠标事件:“mouseover”、“mouseenter”、“mouseleave”、“mousedown”、“keydown”、“keypress”,当然还有一些是和触摸相关的,比如“touchmove”、“touchstart”、“touchend”。对于“click”事件,我觉得还是归于输入设备类比较好点,因为终究还是由输入设备产生的。另外还有一些比较特殊的事件:比如苹果safari中的orientationchange,是手机用户在横向模式和纵向模式下产生的事件。

PS:说到手机端的一些事件,有些小激动。因为公司实习的时候是在手机部门,对于移动端的问题,有一些了解。有时间了跟大家分享下手机端前端开发自己的一些理解,会涉及到手机端上下滑动以及各种特效。想想还有些开心,哈哈!

(2)用户界面事件

一般来说,用户界面就是待操作模块和用户产生的交互。比较常见的就是input框的获得焦点focus事件,失去焦点的blur事件。改变表单元素是值“change”事件,以及提交和取消的“submit”、“reset”。

(3)HTML5特定API

HTML5带来了新的元素和功能,比如视音频元素,<video>和<audio>,他们定义了“waiting”、“playing”等等。同样还有拖放的API,比如“dragstart”、“dragover”等等。

(4)状态变化事件

比如AJAX中的“readystatechange”事件,HTML5中离线应用,“online”、“offline”。当然比较重要的一个是window对象的load事件,当文档和页面中的图片等元素均加载完毕后产生的事件,与之类似的,还有一个“DOMContentLoaded”,当DOM准备就绪产生的事件。

其实在平时的开发中,大家使用比较多的事件也就那么一些,将这些归类整理主要是希望自己对事件的分类能有一个直观的认识。

二、事件代理

1.问题引出

平日里,一提到web前端,大家都比较关注“优化”这个关键字。其中关于优化的方案中,经常提到两点:(1)减少对于DOM节点的操作(2)减少不必要的内存的消耗。今天我们提到的事件代理会在这两个方面有出色表现。

先看下面一个例子,有一个分类列表,需要鼠标停在类别上面的时候显示出这个类别下的子类,简要的代码如下:

//html结构
<ul class="typeList">
        <li id="type1"><a href="#">食品</a></li>
        <li id="type2"><a href="#">服饰</a></li>
        <li id="type3"><a href="#">居家</a></li>
        <li id="type4"><a href="#">数码</a></li>
</ul>
//js代码
    var type1=document.getElementById("type1");
    var type2=document.getElementById("type2");
    var type3=document.getElementById("type3");
    var type4=document.getElementById("type4");
    //这里暂时不考虑兼容性
    type1.addEventListener("mouseover",function(){
        //do something...
        alert(1);
    },false);
    type2.addEventListener("mouseover",function(){
        //do something different...
        alert(2);
    },false);
    type3.addEventListener("mouseover",function(){
        //do something...
        alert(3);
    },false);
    type4.addEventListener("mouseover",function(){
        //do something...
        alert(4);
    },false);

这里只有4个类目,我们可以一个一个的添加,但是如果在一个复杂的环境下,比如有50个类目、100个类目。我们对所有元素都绑定鼠标悬停事件,那么可以想象,这是多么恐怖和劳民伤财的事情。我们需要获取100次DOM节点,需要为函数开辟100个这样的存储空间。

就在这时,好消息来了。“事件代理”隆重出场。

2.什么是事件代理

为解决“事件处理程序过多”问题而提出的方案就是事件代理。事件代理主要是利用了事件冒泡(什么是冒泡,以及与事件捕获的区别,可以参考我的前面的博客),我们只需要至指定一个事件处理程序,就可以管理一系列类似的事件。比如需要对页面中多个按钮绑定click事件,这时,我们只需要对document对象注册一个click处理程序。当点击某个按钮时,事件冒泡会将点击事件传到document对象,这时候绑定的事件处理程序会执行,通过判断事件的发生对象,我们可以对不同的点击产生不同的操作。

好了,表述了这么多,大家有点晕了,下面看具体的代码,以下我选择了mouseover事件来给大家演示:

为了保证适当的兼容性,我们对事件绑定做了处理。

//传入要注册事件的元素,事件类型,以及事件处理函数function addEvent(element,type,func){
     document.addEventListener?element.addEventListener(type,func,false):element.attachEvent("on"+type,func);
}

对于事件处理程序,我们也需要做一些兼容性的处理。

var handler=function(event){
    var e=event||window.event;//兼容性处理,得到event对象
    var relTarget=e.relatedTarget||e.fromElement;//兼容性处理,得到鼠标是从哪里进入目标对象的
    var target=e.target||event.srcElement;//兼容性处理,得到事件的真正发出者
    if(relTarget&&relTarget.nodeName.toLowerCase()=="ul"){
        switch(target.id){
            case "type1":
                console.log(1);
                break;
            case "type2":
                console.log(2);
                break;
            case "type3":
                console.log(3);
                break;
            case "type4":
                console.log(4);
                break;
        }
    }
}

另外,这里要注意二点:

(1)由于是mouseover事件,鼠标在穿过子元素的时候也会产生mouseover事件,所以鼠标放到类别栏的时候,会出现抖动的现象(因为从鼠标li->a->li过程重复触发了mouseover事件)所以我们必须要判断鼠标是否是从子元素移动过来的。如果鼠标移动之前来自ul元素,表示是我们想要的展开列表操作,否则我们不作处理。

(2)由于鼠标可能从浏览器移动过来,在chrome、ie8、ie9下检测relatedTarget是null,FF下表现为undefined,ie7下是[object],另外ie7下鼠标停留在li里面刷新页面,relatedTarget也返回null。所以为了防止空值的出现,需要做出相应的判断if(relTarget&&relTarget.nodeName.toLowerCase()=="ul"){}

3、完整示例

有了前面的准备工作,我们来一个完整的示例

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        *{margin:0;padding:0}
        ul li{list-style:none;float:left;margin:10px;padding:8px;background-color: #ccc;}
        ul{background-color:red;float:left;}
    </style>
</head>
<body>
    <ul id="typeList">
        <li id="type1"><a href="#">食品</a></li>
        <li id="type2"><a href="#">服饰</a></li>
        <li id="type3"><a href="#">居家</a></li>
        <li id="type4"><a href="#">数码</a></li>
    </ul>
</body>
<script type="text/javascript">
var handler=function(event){
    var e=event||window.event;//兼容性处理,得到event对象
    var relTarget=e.relatedTarget||e.fromElement;//兼容性处理,得到鼠标是从哪里进入目标对象的
    var target=e.target||event.srcElement;//兼容性处理,得到事件的真正发出者if(relTarget&&relTarget.nodeName.toLowerCase()=="ul"){
        switch(target.id){
            case "type1":
                console.log(1);
                break;
            case "type2":
                console.log(2);
                break;
            case "type3":
                console.log(3);
                break;
            case "type4":
                console.log(4);
                break;
        }
    }
}
function addEvent(element,type,func){
    document.addEventListener?element.addEventListener(type,func,false):element.attachEvent("on"+type,func);
}

addEvent(document.getElementById("typeList"),"mouseover",handler);
</script>
</html>

从上面的代码中,大家可以发现,把鼠标放到不同的li上面以后,程序会做出不同处理,至此,事件代理已经实现。

4、事件代理的优势

通过上面的示例代码,我们能看到事件代理相比于传统的事件处理程序有以下优势:

(1)对DOM的操作减少,相比于之前处理方式,现在我们只需要引用一次DOM节点。大大减少了对于DOM的引用次数,自然设置事件处理程序的时间也降低了。

(2)整个页面中我们只有一个function对象,减少了内存的消耗,整体性能提升。

(3)用户体验更好,只要可点击元素呈现在我们面前,事件处理程序就能立即触发。以前会出现元素出现了,但是为元素注册的事件处理程序还未注册成功,造成元素不可点击,或点击了没反应。

三、事件代理思想的用处

这块内容感谢司徒正美,下文中的示例代码均来自于这个博客大牛,本人只是理解之后的记录。谢谢你无私的奉献,等我工作了,一定给你支付宝贡献点钱,哈哈!

看下面一段代码:

var delegate = function(client, clientMethod) {
    return function() {
        return clientMethod.apply(client, arguments);
    }
}
var ClassA = function() {
    var _color = "red";
    return {
        getColor: function() {
            console.log("Color: " + _color);
        },
        setColor: function(color) {
            _color = color;
        }
    };
};

var a = new ClassA();
a.getColor();//red
a.setColor("green");
a.getColor();//green
console.log("执行代理!");
var d = delegate(a, a.setColor);
d("blue");
console.log("执行完毕!");
a.getColor(); //blue

由于我们不能直接操作ClassA中的_color,所以,必须通过类提供的对外接口去操作受保护的变量。或者通过delegate创建一个代理对象,改变this的指向,然后操作_color.其实说白了额,这就是call、apply的应用。

四、总结

事件代理可以为我们减少内存空间、提升页面整体性能。如果有必要,大家其实可以对document对象注册事件,这样所有动作都会冒泡到document并得到处理。

本人能力有限,文中有表述不当的地方,希望大家给予指正。如果各位基友和软妹子觉得文章对您有所帮助,你的留言和推荐将对我是莫大的鼓舞!

时间: 2024-12-15 06:00:02

了解javascript中的事件(二)的相关文章

javascript中的事件

在javascript中的事件有三个方面的知识,一是事件流,二是事件处理程序,三是事件对象.下面就我个人的一点理解,分别讲述一下这三个方面的内容. 第一.事件流 事件流指的是事件按照一定的顺序触发.它有两个顺序,分别是自上而下和自下而上. 自上而下的叫做事件捕获,事件捕获指的是事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有祖先元素依次往下传递.在这个过程中,事件会被从文档根到事件目标元素之间各个继承派生的元素所捕获,如果事件监听器在被注册时设置了useC

javaScript中的事件三

javaScript中的事件三 先看两种错误的写法,他们的目的都是:添加两个事件: 错误方式一: window.onload=function (){ alert('event 1'); } window.onload=function (){ alert('event 2') } 错误方式二: window.onload=function (){ var obj=document.getElementById("but"); obj.onclick=function(){ alert

了解javascript中的事件(一)

零.寒暄 由于刚入职,近期事情繁多,今天好不容易中期答辩完事,晚上有一些时间,来给大家分享一篇博文. 这段时间每天写js接触事件比较多,自己会使用,但是用的时候比较混乱,现在系统的整理下,好了,闲话不多说,谈正事! 一.事件概念 什么是事件?说白了,事件是文档或浏览器中发生的特定交互瞬间!比如鼠标点击,滑过等等. 二.事件流 事件流就是描述了页面中接受事件的顺序.在浏览器发展的初期,两大浏览器厂商IE和Netscape互掐,出现了一个坑爹的情况,那就是他们对事件流的解释出现了两中截然相反的定义.

JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获

先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JavaScript 中的事件冒泡与事件捕获</title> </head> <body> <div id="Red" style="width:200px;height:200px;background-color:red;padding:2

Jquery:Jquery中的事件&lt;二&gt;

这几天快忙死了,办了离职还得办入职,完全打乱了我的计划,但是能有一个理想的工作,还是很开心的,以后加把劲,争取把计划再赶上来!不说了,学习!!! 五.事件对象的属性 1.event.type:获取事件的类型,其中event是事件的对象. 2.event.preventDefaule(),在上一个学习笔记中已经有介绍了,该方法是阻止默认的事件事件行为.event.stopPropagation(),该方法的作业是阻止事件的冒泡. 3.event.target,它的作用是获取到触发事件的元素.通过返

javascript中奇怪事件

javascript中奇怪事件 为啥叫奇怪事件了,应该是我目前掌握的知识暂时不能解释这种现象滴呀(也许可以用事件流的概念来解释滴呀) 看布局: #hideInfo{ height:100px; width:100px; background:green; position:absolute; top:20px; left:-90px; } #hideInfo span{ height:100px; width:100px; background:blue; position:absolute;

javascript中的事件与事件处理

在js中事件处理的过程分为三步: 1.发生事件 2.启动事件处理程序 3.事件处理程序做出反应 事件处理程序的调用 1.在javascript中 在javascript中调用事件处理程序,首先要获得要处理对象的引用,然后将要执行的处理函数赋值给对应的事件 2.在html中 在html中分配事件处理程序,只需要在html标记中添加相应的事件,并在其中指定要执行的代码或函数名即可 DOM事件模型: DOM结构是一个树形结构,当一个HTML元素产生一个事件时,该事件会在元素节点与根节点直接的路径传播,

JavaScript中的事件对象

JavaScript中的事件对象 JavaScript中的事件对象是非常重要的,恐怕是我们在项目中使用的最多的了.在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有关的信息.下面将会讲到DOM中的事件对象.IE中的事件对象以及跨浏览器的事件对象三个部分. 对于事件处理程序,大家可以看我的博文<JavaScript中的五种事件处理程序>. 第一部分:DOM事件对象 兼容DOM的浏览器会将一个event对象传入到事件处理程序中,无论是HMTL特性.DOM0级还是

JavaScript中的类型转换(二)

说明: 本篇主要讨论JavaScript中各运算符对运算数进行的类型转换的影响,本文中所提到的对象类型仅指JavaScript预定义的类型和程序员自己实现的对象,不包括宿主环境定义的特殊对象(比如浏览器定义的对象) 上一篇中讨论了JavaScript中原始类型到原始类型的转换,原始类型到对象类型的转换和对象类型到原始类型的转换,这里先提出一个问题 var a = undefined; if(a){ console.log('hello'); }else{ console.log('world')