了解JavaScript事件注册的几种方式

boyanx6天前技术教程3

JS事件类型可以分为三种:

鼠标事件,由某个鼠标动作引发。常用的有click、mouseover、mouseout、mousedown、mouseup、dbclick、mousemove等;

键盘事件,由某个键盘动作引发。常用的有keydown、keypress、keyup;

接口事件,由用户行为的结果引起的事件,而非由用户行为直接引起的;如按下表单的submit按钮,会引起submit事件,由用户点击a链接时会要开新页面并释放当前页,些时会引起unload事件等,常用的有blur、focus、change、contextmenu、load、unload、readystatechange、reset、submit、resize、scroll等。

一旦我们决定使用何种事件来完成交互时所需要做的事情时,就需要注册事件处理程序,事件注册方式有两种模型:

传统模型

行内作为属性。即直接在HTML元素通过添加属性形式来注册,优点是所有浏览器都兼容,缺点是维护难,违背了结构与行为相分离的WEB标准原则,所以不提倡,代码像这样:

<a href="index.html">do</a>

<p>test</p>

值得注意的是大小写的问题,由于HTML对大小写不敏感,所以在过去编写这些事件时按惯例采用的驼峰格式像这样onClick、onMouseOver,但是值得注意的是作为元素的属性写在HTML里这样没有问题,但是如果是在在js环境里这样是不行的,因为js对大小敏感。

结构与行为分离

结构与行为分离的方式是遵循了WEB标准,要想分离必须设置关联钩子,像这样:

<a href="index.html" id="link">do</a>

<p id="test">test</p>

<script>

var link = document.getElementById('link'),

test = document.getElementById('test');

link.onclick = doThis;

test.onclick = doThat;

function doThis(){...}

function doThat(){...}

</script>

需要注意的是这里的函数名后面没有加(),加了表示立即执行,有时候我们想在页面加载完就立即执行一次那就需要加()。还有就是大小写的问题,之前也提到过了,这里的事件名字要小写像这样onclick,否则无法识别。当然还支持另一种形式即匿名函数,像这样:

var link = document.getElementById('link'),

test = document.getElementById('test');

link.onclick = function(){...};

test.onclick = function(){...};

虽然我们大部分时候都是用的这种传统方式,而且也不会发生什么错误,但它还是有它的缺点,那就是覆盖问题,按照代码从上往下的执行顺序,如果一个对象注册了相同的几个事件,那么最后的一个会把前面定义的事件全部覆盖,建议在项目完全由我们自己掌控的情况下可以使用些方法,无兼容性,且简单直观。如需要解决覆盖问题请看下面的高级事件注册模型。

高级模型

此模型主要用来有效解决覆盖问题,但是它有一个兼容性问题,即IE浏览器与其它WEB标准浏览器的事件注册方法不一样,幸运的是,解决这个兼容性问题并不难,我们先看看W3C(WEB标准浏览器阵容支持)和微软(IE系列阵容支持)所支持的高级事件处理程序方法:

obj.addEventListener('click', doThis, false); //添加

obj.removeEventListener('click', doThis, false); //移除

//Microsoft

obj.attachEvent('onclick', doThis); //添加

obj.detachEvent('onclick', doThis); //移除

上面的代码我们可以看出,W3C提供的addEventListener和removeEventListener方法有三个参数:

第一个是事件名称,它是字符串类型的;

第二个是事件发生后要执行的函数,通常我们是不需要立即执行的,所以不带();

第三个参数接收的是一个布尔值,指定事件传递的方式,false表示冒泡,true表示事件捕获。

Microsoft提供的attachEvent和detachEvent方法有两个参数:

第一参数是事件名称,它是字符串类型的,但和W3C不同的是微软它的事件名称需要加上on,和普通模型一样的;

第二参数是事件发生后要执行的函数,和W3C一样

我们可以写个两个通用函数来解决兼容性问题,像这样:

注册事件

addEventSimple(obj, evt, fn, bool){

//对象检测,通常都是将W3C制定的方法判断在前面,因为那些暂时不支持的浏览器或许哪一天就跟随标准了,放在前面这也是提升性能的小技巧

if(obj.addEventListener){

bool = bool || false;

obj.addEventListener(evt, fn, bool);

}else if(obj.attachEvent){

obj.attachEvent('on'+evt, fn);

}

}

//移移注册事件

removeEventSimple(obj, evt, fn, bool){

if(obj.removeEventListener){

bool = bool || false;

obj.removeEventListener(evt, fn, bool);

}else if(obj.detachEvent){

obj.detachEvent('on'+evt, fn);

}

}

addEventSimple接受四个参数,其中前三个是必须的,第四个是可选的

obj指定注册事件的对象,数据类型为Object;

evt指定事件名称,数据类型为String;

fn指定事件发生后要执行的函数;

bool指定事件传递的类型,数据类型为Boolean;

接下来我们就可以这样使用了:

<a href="index.html" id="link">do</a>

<p id="test">test</p>

<script>

var link = document.getElementById('link'),

test = document.getElementById('test');

addEventSimple(link, 'click', doThis);

addEventSimple(link, 'click', doThat);

addEventSimple(test, 'click', doThis);

addEventSimple(test, 'click', doThat);

function doThis(){...}

function doThat(){...}

</script>

这样就不会覆盖了,虽然事件注册高级模型,看似很牛B,但也有它的缺点,除了刚才所说的兼容性问题,还有一个就是它无法移除对象上同一个注册事件绑定的所有执行函数。如果需要移除就必须要知道对象事件注册绑定的执行函数名称如上面的doThis、doThat。而传统模型是可能的:obj.onclick = null。

文/丁向明

做一个有博客的web前端自媒体人,专注web前端开发,关注用户体验,加我qq/微信交流:6135833

http://dingxiangming.com

标签: iscroll.js

相关文章

用JavaScript开发移动原生应用,Facebook正式开源React Native!

在经过前一天Messenger应用平台、Parse物联网开发者工具等惊喜的轰炸,Facebook于今天凌晨在F8开发者大会上正式开源了React Native。不过目前,只有iOS版,Android版...

touch-action踩坑(touch&go)

使用css touch-action的原因在其官方的说明中:是否,以及以何种方式,给定的区域,可以由用户通过触摸屏操作(例如,通过平移或缩放内置的浏览器功能)但我最初并不是因为这个来使用它的,后续会补...

第3章 Vue.js快速精要(vue.js实战)

3.1 组合式API与选项式API对比实践架构差异对比uni-app开发建议// 选项式API适合简单页面 export default { data() { return { count...

&quot;前端开发者不可错过的技能:SSE流式传输助力实时数据更新!&quot;

背景由于大模型通常是需要实时推理的,Web 应用调用大模型时,它的标准模式是浏览器提交数据,服务端完成推理,然后将结果以 JSON 数据格式通过标准的 HTTP 协议返回给前端。但是这么做有一个问题,...

利用 Fluid 自制 Mac 版 Overcast 应用

我喜爱收听播客,健身、上/下班途中,工作中,甚至是忙着做家务时。大多数情况下我会用 Marco Arment开发的Overcast(Freemium)在 iPhone 上收听,这是我目前最喜爱的 Po...

取代JavaScript库的10个现代Web API及详细实施代码

为什么浏览器内置的API你还在用某个臃肿的Javascript库呢?用内置的API有什么好处呢?Web平台经历了巨大演进,引入了强大的原生API,不再需要臃肿的JavaScript库。现代浏览器现已支...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。