浅谈js之事件处理

上一篇是谈的事件流,博客地址:点我;这次我们说说具体的事件处理。

0x00:事件处理程序

现在有三种方式注册事件处理程序:

  • HTML事件处理程序
  • DOM0级事件处理程序
  • DOM2级事件处理程序

001:HTML事件处理程序

就是说给html标签的属性设置事件处理程序;例如:

<p onclick="alert(‘hello‘)">点我</p>

p标签的属性onclick,把它的值设置成javascript代码字符串;这就是早期的js的用法

现在这个方式,用的不多了,是因为HTML与JavaScript代码耦合太紧密。就是说html代码里有javascript代码,现在都讲究行为,样式,结构分离;

还有就是这里的javascript代码字符串中的this,event对象是可以直接使用的。例如:

<p onclick="console.log(this);console.log(event)">点我</p>

打印是这样:

这是因为当指定一串javascript代码作为HTML事件处理程序属性值时,浏览器会把代码字符串为类似下面的函数中运行:

function (event) {
    with(document) {
        with(this.form || {}) {
            with(this) {
                //这里是代码字符串
            }
        }
    }
}

这就解释了为什么能直接使用event对象和this对象了。

但是还要注意有时我们也这样用

<body>
<p onclick="aa();">点我</p>
<script type="text/javascript">
function aa() {
    console.log(this);
    console.log(event);
}
</script>
</body>

这样打印什么呢?

这时候的this就是window对象,这就是this对象有的时候让人很难确定到底指的那个作用域。这这里的函数就是window调用的;还有就是如果你想引用指向元素的作用域的this,你可以向这个函数把这个this对象传递当参数过去,就像这样:

<body>
<p onclick="aa(this)">点我</p>
<script type="text/javascript">
function aa(_this) {
    console.log(_this);
    console.log(event);
}
</script>
</body>

打印:

002:DOM0级事件处理程序

  就是说,首先获取对这个元素DOM对象的引用,用DOM的getElementById()等这种方式获取到对这个元素对象的引用,然后就是每个事件都在这个对象上用相应的属性,例如click事件,那么这个对象就有一个onclick属性与之对应,那你在这个对象的属性上绑定事件处理程序,例obj.onclick = function() {//相应代码};那么当你在点击的时候就会触发事件了;

这种方式大家都太熟悉了我就不举例了。

这种方式的优点就是几乎所有浏览器都兼容这种方式,一般不存在兼容性问题,我们平时写代码现在也用的很多。简单方便嘛。

但是他也是有缺点的。每个事件元素目标对于每个事件类型只能最多注册一个事件处理程序。

例如:

obj.onclick = function () {
    //这里是代码1
};
obj.onclick = function () {
//这里是代码2
}

那么后面的会覆盖前面的,前面这个注册程序就不会执行了。

这种事件处理的程序在事件流中只能会冒泡;之前的在事件流说过这个;

要是想删除这个事件处理程序,就这样:

obj.onclick = null;

003:DOM2级事件处理程序

DOM2级事件定义了两个方法,addEventListener()方法和removeEventListener()方法来处理和删除事件处理程序。它们可以接收三个参数,第一个参数:要处理的事件名,是一个字符串,但是要记得不要加“on”作为前缀,第二个参数:作为事件处理的函数,第三个参数:一个布尔值,这个布尔值为true时,那就在事件捕获阶段调用事件处理程序,如果是false那就在冒泡阶段调用事件处理程序。ps。这两个方法支持除IE8及以下的其他版本的所有浏览器

它的主要优点是可以为同一个对象的同一个事件绑定多个事件处理程序。并且注册的多个事件是按顺序执行的;

上例子:

<p id="test">点我</p>
<script type="text/javascript">
var test = document.getElementById("test");
    test.addEventListener("click",function () {
        alert("first click");
    },false);  test.addEventListener("click",function () {  alert("secend click");  },false);</script>

如果你想移除事件处理程序,你就需要用到removeEventListener()方法,它也接收三个参数,这三个参数要和你用addEventListener添加事件时的参数一样,必须要一模一样;并且如果addEventListener()的第二个参数,如果是匿名函数,那么用removerEventListener()是删除不了的;并且它也就只能处理用addEventListener注册的事件,那么用DOM0级注册的事件是不能用它删除的。

上离子:

test.addEventListener("click",fn,false);
test.removeEventListener(‘click‘,fn,false);

这样就跟你没有注册事件似的;

但是如果你这样:

test.addEventListener("click",fn,false);
test.addEventListener("click",fn,false);
test.addEventListener("click",fn,false);

却只会弹出一个alert,而不是三个,这就是如果你使用相同的参数在同一对象调用多次,处理程序只是注册一次;

IE永远都是一朵奇葩,IE8及以下不支持,但是有两个跟DOM2级的方法相似的事件处理方法,attachEvent()和detachEvent()方法。需要两个参数,第一参数:事件名,注意要在事件名前加“on”,第二个参数:事件处理程序函数;它也是可以绑定多个事件处理程序的;

这两个方法支持IE5 ——IE10,IE11就不再支持了;

我就说说他和标准DOM2级的不同,相同点就不提了,

  1.事件处理的作用域:

    不管是DOM0级还是DOM2级他们的事件处理程序都是在它们所属元素的的作用域中运行,但是attachEvent却不是,事件处理程序会在全局作用域中运行,即事件处理程序中的this === window的,一定要记住这里面的this是指向window的

  2.当调用多个事件处理程序时:

    第一点:当为同一DOM对象同一个事件添加多个不同的事件处理程序函数时:在IE5-IE8,这个调用顺序也很奇葩,后注册的函数,先被调用,但是IE9,IE10这个顺序就变过来了。

    第二点:当为同一个DOM对象的同一个事件添加多个相同的事件处理程序函数时:在IE5——IE8是你添加几个就执行几个,但是在IE9,10却不是这样,它只会为你注册一个事件处理程序,即你添加多个执行一个;ps。但是你如果用匿名函数,其实每个匿名函数都是不同的函数。即使你里面的内容一样。

由于IE的这种奇葩,我们想用DOM2级的方法,但是又要照顾IE8及以下,这就产生了一个跨浏览器的事件处理程序

//通过能力检测来确定浏览器支持
var EventUtil = {
    //param ele 元素对象
    //param type 事件类型
    //param handler 事件处理程序函数
    addHandler: function (ele,type,handler) {
        if(ele.addEventListener) {
            ele.addEventListener(type,handler,false);
        } else if (ele.attachEvent) {
            ele.attachEvent("on" + type,handler);
        } else {
            ele["on" + type] = handler;
        }
    },

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

跨浏览器事件处理程序

这个程序没有考虑IE的attachEvent()函数的作用域问题,也就是说它里面this不能用。但你可以直接引用这个对象,或者用event对象的srcElement获取到这个对象;

0x01 事件对象

在触发DOM上的事件时就会自动产生一个事件对象,这个对象包含这个事件的相关信息。

  001.获取event

就是直接在事件处理程序函数传递第一个参数就是event对象,这个是浏览器自动传递的。但是我今天亲测了一下发现:


DOM0级


DOM2级(addEventListener方法)


attachEvent

(仅IE5—IE10支持)


chrome


支持传参;

也支持window.event


支持传参;

也支持window.event


IE


支持传参;

也支持window.event

(但是IE8及以下不支持传参方式)


支持传参;

也支持window.event

(IE9-IE11支持下)


支持传参;

也支持window.event


firefox


仅支持传参;


仅支持传参;


opera


支持传参;

也支持window.event


支持传参;

也支持window.event

我用的浏览器都是最新的;

但是一般为了兼容性一般在用到的是时候这样写:

event = event || window.event;

002.取消默认操作行为

比如a标签只要你点击就跳转到href属性值的url,要是你不想让它跳转,你就要阻止默认行为;

DOM0级事件处理程序中的取消默认事件:方式1:在事件处理程序的函数中返回值设置为false,这个所有浏览器都支持;

                   方式2:event对象的方法,这样用:event.preventDefault()方法,但是这个只是一部分浏览器支持:chrome,opera,IE11;那就是说其他的都不支持了;还有IE自家的returnValue属性,event.returnValue = false;也可取消默认行为,仅IE5-IE10支持;

总结:如果你想用,那你就用返回值这种方式,兼容性最好了。

DOM2级中:那就直接用event.preventDefault();但是IE的attachEvent中要取消默认行为,要用event.returnValue = false;

003.阻止事件传播(冒泡或捕获)

DOM0级和DOM2级都可以用event对象的stopPropagation(),但是IE8及以下不支持;

IE8及以下可以用事件对象的cancelBubble属性,设置为true就取消冒泡;

004.在介绍一个event对象的一个type属性的用法:它指的是事件目标

在例子中说明:

function handler (evt) {
    switch(evt.type) {
        case "click":
        //相应代码
         console.log("clicked");
        break;
        case "mouseover":
        // 相应代码
        console.log("mouseover");
        break;
        case "mouseout":
        //相应代码
        console.log("mouseout");
        break;
    }
}
test.onclick = handler;
test.onmouseover = handler;
test.onmouseout = handler;

多了不解释;

005.event中的属性

不同的事件它的event对象所包含的属性也会有所不同。

下列只是列出了每个事件都会有的

属性/方法 类型 读/写 说明
bubbles Boolean read 表明事件是否冒泡
cancelable Boolean read 表明是否可以取消事件的默认行为
currentTarget Element read 其事件处理程序当前正在处理事件的那个元素
defaultPrevented Boolean read 为true表示已经调用了preventDafult()
detail Integer read 与事件相关的细节信息
eventPhase Integer read
表明调用事件处理程序的阶段:1表示捕获阶段

2表示处于目标,3表示冒泡阶段

preventDefault() Function read 取消事件的默认行为。如果cancelable是true,则可以使用这个方法
stopImmediatePropagation() Function read 取消事件的进一步冒泡或捕获,同时阻止任何事件处理程序被调用
stopPropagation() Function read 取消事件的进一步捕获或冒泡
target Element read 事件目标
trusted Boolean read 为true表示事件是浏览器生成的,false表示是由开发人员生成的
type String read 被触发的事件类型
view AbstractView read 与事件相关的抽象视图

其实还有很多,比如鼠标事件还要有坐标位置信息,如clientX,clientY,screenX,screenY等,但是在键盘事件中就没有坐标信息

IE中所共有的

属性/方法 类型 读写 说明
cancelBubble Boolean read,write 默认为false,但是将其设置为true就取消事件的冒泡,(与DOM中的stopPropagation对应
returnValue Boolean read,write 默认为true,设置为false取消事件的默认行为(与DOM的preventDefault)
srcElement Element read 事件目标(与DOM中的target对应)
type String read 被触发的事件类型

006.跨浏览器事件对象

var EventUtil = {
    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;
        }
    }
};

如有不准或错误,欢迎指正!

参考:javascript高级程序设计;

   javasript权威指南;

时间: 2024-10-21 01:55:24

浅谈js之事件处理的相关文章

浅谈 js eval作用域

就简单聊下如何全局 eval 一个代码. var x = 1; (function () { eval('var x = 123;'); })(); console.log(x); 这个代码得到的是 1 而不是 123如果想让 eval 执行的代码是全局的,那么有几种方法. var x = 1; (function () { window.eval('var x = 123;'); })(); console.log(x); 这个方法标准浏览器都可以得到 123 而IE6-8则依然是 1 相同的

浅谈 js 正则之 test 方法

原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. ? 1 2 3 4 5 var re = /\d/; console.log( re.test("1") ); console.log( re.test("1") ); console.log( re.test("1") ); console.log( re.test("1"

浅谈 js 语句块与标签

原文:浅谈 js 语句块与标签 语句块是什么?其实就是用 {} 包裹的一些js代码而已,当然语句块不能独立作用域.可以详细参见这里<MDN block> 也许很多人第一印象 {} 不是对象字面量么?怎么成了语句块了?如果在赋值语句或者表达式里用的时候,确实是对象字面量,如: var a = {}; ({toString:function(){return "hehe"}}) + "..."; 是不是很有意思..但是直接使用如: {toString: fu

浅谈JS之AJAX

0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HTTP和web服务器进行数据交换(用户不知道也感觉不出来,就跟桌面应用程序似的进行数据交互),它不会导致页面重新加载,这样才有更好的用户体验. Ajax是基于以下开放标准: javascript(DOM) css html xml(json) 通俗的说就是使用了javascript(DOM)的XMLH

浅谈 js 下 with 对性能的影响

这几天多次看到有博主们在写 with 的文章,这货确实非常方便,但是却是个性能杀手,所以一直都是上不得台面的.那么他究竟会让效率低下到什么程度呢?先来看下 with 是如何的便捷吧.. // 正常调用 console.log(location.host); console.log(location.pathname); // 在 with 下 with (location) { console.log(host); console.log(pathname); } 如果不影响性能,确实是非常霸气

浅谈 js 数字格式类型

原文:浅谈 js 数字格式类型 很多人也许只知道 123,123.456,0xff 之类的数字格式.其实 js 格式还有很多数字格式类型,比如 1., .1 这样的,也有 .1e2 这样的. 可能有人说这是什么个格式?其实还不止呢.1          //11.2       //1.21.2e3    //12001.2e+3  //12001.2e-3  //0.0012.12e+2 //12-.12e-2 //-0.0012 当然这些只是十进制.我们来说说 八进制 和 十六进制.0x00

浅谈 js 字符串 trim 方法之正则篇

position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流

从window.console&amp;&amp;console.log(123)浅谈JS的且运算逻辑(&amp;&amp;)

从window.console&&console.log(123)浅谈JS的且运算逻辑(&&) 作者:www.cnblogs.com  来源:www.cnblogs.com  发布日期:2015-03-01 一.JS的且运算记得最开始看到window.console&&console.log(123),当时知道能起什么作用但是没有深入研究,最近在研究后总算弄明白了.要理解这个,首先得明白三个知识点第一:短路原则这个大家都非常清楚的了,在做且运算的时候,“同真

浅谈 js 对象 toJSON 方法

前些天在<浅谈 JSON.stringify 方法>说了他的正确使用姿势,今天来说下 toJSON 方法吧.其实我觉得这货跟 toString 一个道理,他是给 stringify 方法字符串化的时候调用的.看下 MDN 官方文档吧<toJSON behavior>.非常简单,但是要注意的是他和 stringify 方法第二个参数稍微有点不同.因为 stringify 第二个参数是回调函数时,只是对当前 key 对应的值进行修改.而 toJSON 则是对当前对象进行修改.例如: v