Javascript事件处理进阶
这篇文章是我在看乌龟书《编写可维护的Javascript》发现的一篇写的非常好的章节,在这里我并不会教大家什么是绑定事件等比较基础的事。有兴趣了解DOM事件的同学们,可以去w3cschool查阅。
事件绑定
大家都知道前端开发中,事件处理是非常重要的。我们在view层的交互,都是通过绑定事件到UI上,然后我们再处理这些事件。让我们写一个事件绑定的函数先。
var addListener = function(target, type, listener){
if(target.addEventListener){
//2级的DOM事件绑定
target.addEventListener(type, listener, false);
}else if(target.attchEvent){
//IE事件绑定
target.attchEvent("on" + type, listener);
}else{
//0级的DOM事件绑定,也是最可靠的,但只可单次绑定
target["on" + type] = listener;
}
}
上面写了一个兼容性强的DOM事件绑定,但希望大家要注意:DOM0级的事件只可单次绑定,再绑定会导致覆盖的问题出现。
常见用法
当事件触发后,会有一个event回调参数传入事件处理中。而所有的有关事件的信息都会储存在event对象中。我们假设需要做一个点击,并在鼠标的位置弹出框。我们是这样写的。
var handlerClick = function(event){
var popup = document.getElementById("popup");
popup.style.left = event.clientX;
popup.style.top = event.clientY;
popup.className = "active";
}
addListener(element, "click", handlerClick);
乍一看,这是没什么问题的。确实它可以运行的很好,这毋庸置疑。可是你是否有考虑过,你的事件处理程序中,却包含了与用户行为无关的应用逻辑,也就是指弹框这个行为。或许当我们使用mousemove事件时,也需要这段应用逻辑,并可以为此单独拓展一些行为时,我们就只能通过copy同样的应用逻辑并在里面添加自己需要的代码。
而另一个同样明显的缺点,则是关于测试的。如果测试需要通过模拟触发事件的形式进行的,现有的测试框架并不是特别稳定和理想。而将隔离出应用逻辑,可以使我们直接触发功能代码。
规则1:隔离应用逻辑
那我们应该如何拆分应用逻辑和事件处理代码呢?首先我们使用模块模式,将所有有关事件处理的函数放在里面,也能防止全局污染。一起来看看:
var MyAppEvent = {
handlerClick: function(event){
this.showPopup(event);
alert("click it!");
},
handlerMousemove: function(event){
this.showPopup(event);
}
showPopup: function(event){
var popup = document.getElementById("popup");
popup.style.left = event.clientX;
popup.style.top = event.clientY;
popup.className = "active";
}
}
//绑定事件
addListener(element, "click", function(event){
MyAppEvent.handlerClick(event);
})
我们将应用逻辑转移到了showPopup函数中,这样使得弹出框的应用逻辑独立了出来,我们就可以在事件处理上更加灵活。例如我在handlerClick加了一个alert函数,这并不会影响到handlerMousemove里弹框的操作。当然这只是拆解程序代码的第一步。
规则2:不要分发事件对象
我们可以看到在MyAppEvent中,event参数传的到处都是。这其实是没问题的,只是有点无节制的分发罢了。因为我们在showPopup函数中,仅仅只是用到了event对象里的clientX和clientY。其它的都是不必要的。我们应该认为,关于应用逻辑,它其实是不能依赖太多东西的。包括触发的事件(这个我们刚才已经妥善处理了),还有就是回调参数event。
若我们不明确应用逻辑要做什么事情时,直接传入event参数,无可厚非。可是这一次我们其实是明确知道我们仅仅是需要一个x坐标和y坐标,所以我们可以通过事件处理函数对event进行筛选。
var MyAppEvent = {
handlerClick: function(event){
this.showPopup(event.clientX, event.clientY); //改变的地方
alert("click it!");
},
handlerMousemove: function(event){
this.showPopup(event.clientX, event.clientY); //改变的地方
}
showPopup: function(x, y){ //改变的地方
var popup = document.getElementById("popup");
popup.style.left = event.x;
popup.style.top = event.y;
popup.className = "active";
}
}
//绑定事件
addListener(element, "click", function(event){
MyAppEvent.handlerClick(event);
})
那这样写之后,当我们要对这个应用逻辑进行测试时,就不再依赖event对象了,我们可以直接传入应用逻辑所期盼的参数。在这里就是有关x,y的坐标。
// API的参数更加明确,不再依赖event
MyAppEvent.showPopup(10, 10);
当event被提取出来后,应用逻辑则更为独立,不过还有一些小细节要处理。就是关于阻止默认行为event.preventDefault()与阻止冒泡行为event.stopPropagation(),则也需要在事件处理函数中提前处理。
最后我们把事件处理程序和应用逻辑之间的分工清晰的分开后,我们可以在很多地方轻松使用相同的业务逻辑,包括前端开发者最头疼的测试代码。
Javascript事件处理进阶的更多相关文章
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
- javascript入门进阶(一)
javascript 入门进阶 这里主要讲解一下在入门阶段很难注意的一些知识点,不一定有用.但是会了总比不会强. 1.HTML为<script>标签准备的6个属性: -async:可选.表 ...
- javascript事件处理解析
一.什么是事件!(w3c解释) 事件是可以被 JavaScript 侦测到的行为. JavaScript 使我们有能力创建动态页面.事件是可以被 JavaScript 侦测到的行为. 网页中的每个元素 ...
- JavaScript事件处理的三种方式(转)
一.什么是JavaScript事件? 事件(Event)是JavaScript应用跳动的心脏,也是把所有东西粘在一起的胶水,当我们与浏览器中Web页面进行某些类型的交互时,事件就发生了. 事件可能是用 ...
- 使用AmplifyJS和JQuery编写更好更优雅的javascript事件处理代码
事件(或消息)是一种经常使用的软件设计模式.可以减少消息处理者和消息公布者的之间的耦合,比方J2EE里面的JMS规范.设计模式中的观察者模式(也叫公布/订阅模式).这对于javascript代码相同适 ...
- 私人定制javascript事件处理机制(浅谈)
看到园子里关于事件监听发表的文章,我都有点不好意思写了.不过想想我的题目以私人定制作开头也就妥妥地写吧. 事件相关概念 1.事件类型 发生事件的字符串 有传统事件类型 比如表单.window事件等 D ...
- JavaScript的进阶之路(七)客户端JavaScript知识点总结
一.客户端JavaScript主要是BOM DOM的操作和js脚本的兼容性.互用性.可访问性.安全性的应用.以及一些框架的引用. 二.BOM:浏览器对象模型 主要介绍window对象 1.定时器:se ...
- javascript——事件处理模型(DOM 和 IE)
javascript的事件处理模型分为 DOM事件处理模型和 IE事件处理模型. 一.DOM事件流模型 DOM事件流分为三个阶段:捕获阶段.目标阶段.冒泡阶段. 捕获阶段:自上而下,由document ...
- 【WIP】客户端JavaScript 事件处理
创建: 2017/10/15 完成: 2017/10/15 更新: 2017/11/04 加粗事件的参数 更新: 2017/12/12 增加事件处理时获取事件对象的方法 更新: 2019/05/2 ...
随机推荐
- java中时间的获取(二)
java中时间的获取2 /** * 获取数据库操作记录时间 */ public static String getOpreateDbTime() { Calendar c = Calendar.get ...
- Codeforces Round #272 (Div. 2) C. Dreamoon and Sums (数学 思维)
题目链接 这个题取模的时候挺坑的!!! 题意:div(x , b) / mod(x , b) = k( 1 <= k <= a).求x的和 分析: 我们知道mod(x % b)的取值范围为 ...
- win8 iis安装及网站发布
win8 iis安装及网站发布 系统:win8 环境:vs2012 一:安装IIS 比较win7的安装来说,多选了几个钩钩,不然会报错,偶就遇到这样的错误. 控制面板->程序和功能->启动 ...
- 使用Aspose.Cells组件生成Excel文件
生成带表头的Excel文件,格式如下显示. 当然更复杂的一些也可以通过 合并单元格的方法 public void Merge(int firstRow, int firstColumn, int to ...
- window+git+AndroidStudio+github
1. 安装配置git 安装:需要从网上下载一个,然后进行默认安装即可.安装完成后,找到 “Git Bash”,点击: 配置: 注意:name和email 只是用来标识身份,但是一定要配置好 2. St ...
- [Mac][MySQL]如何启动MySQL Server
方法来自 MySQL 5.7官方手册 http://dev.mysql.com/doc/refman/5.7/en/osx-installation-launchd.html 有两种方法,另一种是命令 ...
- 用 Xcode 开发 Cydia Substrate 插件(一)
关于这方面的中文资料太少了,以至于可能很多对插件开发感兴趣的孩子们都不知从何下手,于是呢我就写了这篇文章,希望对你能有所帮助.如果你觉得文章内容有什么错误呢也请提出来. 准备开发环境 1. 从 App ...
- 09day2
多米诺骨牌 递推+高精度 [问题描述] Jzabc 对多米诺骨牌有很大兴趣,然而他的骨牌比较特别,只有黑色的和白色的两种.他觉得如果存在连续三个骨牌是同一种颜色,那么这个骨牌排列便是不美观的.现在他有 ...
- Python网页解析
续上篇文章,网页抓取到手之后就是解析网页了. 在Python中解析网页的库不少,我最开始使用的是BeautifulSoup,貌似这个也是Python中最知名的HTML解析库.它主要的特点就是容错性很好 ...
- JBPM4入门——5.流程定义的发布、查询、删除
本博文只是简要对JBPM4进行介绍,如需更详细内容请自行google 链接: JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流 ...