很多DOM对象都有原生的事件支持,向div就有click、mouseover等事件,事件机制可以为类的设计带来很大的灵活性,相信.net程序员深有体会。随着web技术发展,使用JavaScript自定义对象愈发频繁,让自己创建的对象也有事件机制,通过事件对外通信,能够极大提高开发效率。

简单的事件需求

事件并不是可有可无,在某些需求下是必需的。以一个很简单的需求为例,在web开发中Dialog很常见,每个Dialog都有一个关闭按钮,按钮对应Dialog的关闭方法,代码看起来大概是这样

<!DOCTYPE html>
<html><head><title>Test</title><style type="text/css" >.dialog{position:fixed;width:300px;height:300px;

z-index:30; 
                top:50%; left:50%; 
                margin-top:-200px; margin-left:-200px; 
                box-shadow:2px 2px 4px #ccc; 
                background-color:#f1f1f1; 
                display:none; 
            } 
            
            .dialog .title 
           { 
                font-size:16px; 
                font-weight:bold; 
                color:#fff; 
                padding:4px; 
                background-color:#404040; 
            } 
            
            .dialog .close 
           { 
                width:20px; 
                height:20px; 
                margin:3px; 
                float:right; 
                cursor:pointer; 
            } 
        </style> 
    </head> 
    <body> 
    
    <inputtype="button" value="Dialog Test" onclick="openDialog();"/> 
    
    <divid="dlgTest" class="dialog"> 
        <imgclass="close" alt="" src="data:images/close.png"> 
        <divclass="title">Dialog</div> 
        <divclass="content"> 
        
        </div> 
    </div> 
    
    <scripttype="text/javascript"> 
        function Dialog(id){ 
           this.id=id; 
           var that=this; 
            document.getElementById(id).children[0].onclick=function(){ 
                that.close(); 
            } 
        } 
        
        Dialog.prototype.show=function(){ 
           var dlg=document.getElementById(this.id); 
            dlg.style.display='block'; 
            dlg=null; 
        } 
        
        Dialog.prototype.close=function(){ 
           var dlg=document.getElementById(this.id); 
            dlg.style.display='none'; 
            dlg=null; 
        } 
   </script> 
    
    <scripttype="text/javascript"> 
        function openDialog(){ 
           var dlg=new Dialog('dlgTest'); 
            dlg.show(); 
        } 
   </script> 
    </body> 
<html>

这样在点击button的时候就可以弹出Dialog,点击关闭按钮的时候隐藏Dialog,看起来不错实现了需求,但总感觉缺点儿什么,一般Dialog显示的时候页面还会弹出一层灰蒙蒙半透明的罩子,阻止页面其它地方的点击,Dialog隐藏的时候罩子去掉,页面又能够操作。加些代码添个罩子。

在body顶部添加一个pagecover

<div id="pageCover" class="pageCover"></div>

为其添加style

.pageCover{width:100%;height:100%;position:absolute;z-index:10;background-color:#666;opacity:0.5;display:none;}

为了打开的时候显示page cover,需要修改openDialog方法

function openDialog(){var dlg=new Dialog('dlgTest');document.getElementById('pageCover').style.display='block';dlg.show();}

效果很不错的样子,灰蒙蒙半透明的罩子在Dialog弹出后遮盖住了页面上的按钮,Dialog在其之上,这时候问题来了,关闭Dialog的时候page cover仍在,没有代码其隐藏它,看看打开的时候怎么显示的page cover,关闭的时候怎么隐藏行了! 还真不行,打开的代码是页面button按钮的事件处理程序自己定义的,在里面添加显示page cover的方法合情合理,但是关闭Dialog的方法是Dialog控件(虽然很简陋,远远算不上是控件)自己的逻辑,和页面无关,那修改Dialog的close方法可以吗?也不行!有两个原因,首先Dialog在定义的时候并不知道page cover的存在,这两个控件之间没有什么耦合关系,如果把隐藏page cover逻辑写在Dialog的close方法内,那么dialog是依赖于page cover的,也就是说页面上如果没有page cover,dialog就会出错。而且Dialog在定义的时候,也不知道特定页面的page cover id,没有办法知道隐藏哪个div,是不是在构造Dialog时把page cover id传入就可以了呢? 这样两个控件不再有依赖关系,也能够通过id查找到page cover DIV了,但是如果用户有的页面需要弹出page cover,有的不需要怎么办?

这是就事件大显身手的时候了,修改一下dialog 对象和openDialog方法

function Dialog(id){this.id=id;this.close_handler=null;var that=this;document.getElementById(id).children[0].οnclick=function(){that.close();if(typeof that.close_handler=='function'){that.close_handler();}}}

function openDialog(){var dlg=new Dialog('dlgTest');document.getElementById('pageCover').style.display='block';dlg.close_handler=function(){document.getElementById('pageCover').style.display='none';}dlg.show();}

在Dialog对象内部添加一个句柄,关闭按钮的click事件处理程序在调用close方法后判断该句柄是否为function,是的话就调用执行该句柄。在openDialog方法中,创建Dialog对象后对句柄赋值为一隐藏page cover方法,这样在关闭Dialog的时候就隐藏了page cover,同时没有造成两个控件之间的耦合。这一交互过程就是一个简单的 定义事件——绑定事件处理程序——触发事件的过程,DOM对象的事件,比如button的click事件也是类似原理。

高级一点的自定义事件

上面举的小例子很简单,远远不及DOM本身事件精细,这种简单的事件处理有很多弊端

1.没有共同性。如果在定义一个控件,还得写一套类似的结构处理

2.事件绑定有排斥性。只能绑定了一个close事件处理程序,绑定新的会覆盖之前绑定

3.封装不够完善。如果用户不知道有个 close_handler的句柄,就没有办法绑定该事件,只能去查源代码

逐个分析一下这几个弊端,弊端一很熟悉,使用过面向对象的同学都可以轻易想到解决方法——继承;对于弊端二则可以提供一个容器(二维数组)来统一管理所有事件;弊端三的解决需要和弊端一结合在自定义的事件管理对象中添加统一接口用于添加/删除/触发事件

function EventTarget(){this.handlers={};}EventTarget.prototype={constructor:EventTarget,addHandler:function(type,handler){if(typeof this.handlers[type]=='undefined'){this.handlers[type]=new Array();}this.handlers[type].push(handler);},removeHandler:function(type,handler){if(this.handlers[type] instanceof Array){var handlers=this.handlers[type];for(var i=0,len=handlers.length;i<len;i++){if(handler[i]==handler){handlers.splice(i,1);break;}}}},trigger:function(event){if(!event.target){event.target=this;}if(this.handlers[event.type] instanceof Array){var handlers=this.handlers[event.type];for(var i=0,len=handlers.length;i<len;i++){handlers[i](event);}}}}

addHandler方法用于添加事件处理程序,removeHandler方法用于移除事件处理程序,所有的事件处理程序在属性handlers中统一存储管理。调用trigger方法触发一个事件,该方法接收一个至少包含type属性的对象作为参数,触发的时候会查找handlers属性中对应type的事件处理程序。写段代码测试一下。

function onClose(event){alert('message:'+event.message);}var target=new EventTarget();target.addHandler('close',onClose);//浏览器不能帮我们创建事件对象了,自己创建一个var event={type:'close',message:'Page Cover closed!'};target.trigger(event);

至此后连个弊端一解决,应用一下继承解决第一个弊端,下面是寄生式组合继承的核心代码,这种继承方式是目前公认的JavaScript最佳继承方式

function extend(subType,superType){var prototype=Object(superType.prototype);prototype.constructor=subType;subType.prototype=prototype;}

最后写成的版本就是这样的

<!DOCTYPE html>
<html><head><title>Test</title><style type="text/css" >html,body{height:100%;width:100%;padding:0;margin:0;}.dialog{position:fixed;width:300px;height:300px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;box-shadow:2px 2px 4px #ccc;background-color:#f1f1f1;z-index:30;display:none;}.dialog .title{font-size:16px;font-weight:bold;color:#fff;padding:4px;background-color:#404040;}.dialog .close{width:20px;height:20px;margin:3px;float:right;cursor:pointer;}.pageCover{width:100%;height:100%;position:absolute;z-index:10;background-color:#666;opacity:0.5;display:none;}</style></head><body><div id="pageCover" class="pageCover"></div><input type="button" value="Dialog Test" onclick="openDialog();"/><div id="dlgTest" class="dialog"><img class="close" alt="" src="data:images/close.png"><div class="title">Dialog</div><div class="content"></div></div><script type="text/javascript">            function EventTarget(){this.handlers={};}EventTarget.prototype={constructor:EventTarget,addHandler:function(type,handler){if(typeof this.handlers[type]=='undefined'){this.handlers[type]=new Array();}this.handlers[type].push(handler);},removeHandler:function(type,handler){if(this.handlers[type] instanceof Array){var handlers=this.handlers[type];for(var i=0,len=handlers.length;i<len;i++){if(handler[i]==handler){handlers.splice(i,1);break;}}}},trigger:function(event){if(!event.target){event.target=this;}if(this.handlers[event.type] instanceof Array){var handlers=this.handlers[event.type];for(var i=0,len=handlers.length;i<len;i++){handlers[i](event);}}}}</script><script type="text/javascript">function extend(subType,superType){var prototype=Object(superType.prototype);prototype.constructor=subType;subType.prototype=prototype;}</script><script type="text/javascript">function Dialog(id){EventTarget.call(this)this.id=id;var that=this;document.getElementById(id).children[0].onclick=function(){that.close();}}extend(Dialog,EventTarget);Dialog.prototype.show=function(){var dlg=document.getElementById(this.id);dlg.style.display='block';dlg=null;}Dialog.prototype.close=function(){var dlg=document.getElementById(this.id);dlg.style.display='none';dlg=null;this.trigger({type:'close'});}</script><script type="text/javascript">function openDialog(){        var dlg=new Dialog('dlgTest');dlg.addHandler('close',function(){document.getElementById('pageCover').style.display='none';});document.getElementById('pageCover').style.display='block';dlg.show();}</script></body>
<html>

最后

这样解决了几个弊端看起来就完美多了,其实可以把打开Dialog显示page cover也写成类似关闭时事件的方式了。当代码中存在多个部分在特定时刻相互交互的情况下,自定义事件就非常有用了。如果每个对象都有其它对象的引用,那么整个代码高度耦合,对象改动会影响其它对象,维护起来困难重重。自定义事件使对象解耦,功能隔绝,这样对象之间实现了高聚合。

本文转自魏琼东博客园博客,原文链接:http://www.cnblogs.com/dolphinX/p/3254017.html,如需转载请自行联系原作者

JavaScript自定义事件相关推荐

  1. Javascript自定义事件功能与用法实例分析

    原文地址:https://www.jb51.net/article/127776.htm 本文实例讲述了javascript自定义事件功能与用法.分享给大家供大家参考,具体如下: 概述 自定义事件很难 ...

  2. JavaScript自定义事件--高级技巧

    观察者模式 事件是JavaScript和浏览器交互的主要途径.事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术. 观察者模式:由两类对象组成,主体和观察者,主体负责发布事件,观察者通过订 ...

  3. javascript自定义事件原理

    我们都知道,鼠标点击click,触屏的touch等事件,可以触发相应的事件处理程序,也可以为这些事件添加事件处理程序,实际开发过程中可供我们使用的事件很少,click.doubleclick,mous ...

  4. javascript自定义事件应用实例

    可以先看例子 从 js 自定义事件 里知道:元素A通过dispatchEvent方法触发的事件,只有A上注册的监听器才能监听得到. 我们想要的效果是,别的对象干了某件事之后, 发个消息给我们,好让我们 ...

  5. JavaScript 自定义事件、触发事件

    1. 自定义事件的基本步骤 创建事件. var event = document.createEvent('Event'); 初始化事件[参数:事件类型.事件是否在DOM中冒泡.是否可以用 preve ...

  6. html 自定义js,js 自定义事件

    js怎么自定义事件,并能让用on事件监听 你这个问题全部内容应该是如下吧: 在视频播放的时候,能够用on监听事件的触发,如下: player.on('pause',function(){ consol ...

  7. 【JS】512- JS 自定义事件如此简单!

    在前端开发世界中,JavaScript 和 HTML 之间往往通过 事件 来实现交互.其中多数为内置事件,本文主要介绍 JS自定义事件概念和实现方式,并结合案例详细分析自定义事件的原理.功能.应用及注 ...

  8. Javascript框架的自定义事件(转)

    很多 javascript 框架都提供了自定义事件(custom events),例如 jquery.yui 以及 dojo 都支持"document ready"事件.而部分自定 ...

  9. 如何在JavaScript中使用自定义事件

    2019独角兽企业重金招聘Python工程师标准>>> JavaScript 的事件处理是所有浏览器端程序的基本必备技巧.当目标元素的事件被触发时,比如按钮被点击,鼠标移动,或者是表 ...

最新文章

  1. node 进阶 | 通过node中如何捕获异常阐述express的特点
  2. 第三次学JAVA再学不好就吃翔(part20)--面向对象
  3. 深度学习目标检测之 YOLO v2
  4. 微信支付get_brand_wcpay_request:fail
  5. Java 读取excl
  6. nginx配置和前端跨域问题
  7. windows下mysql5.6安装
  8. DataBseDesign工作笔记004---PowerDesigner导入sql脚本生成物理模型
  9. 西安工程大学计算机是几本专业,2016年西安工程大学计算机科学与技术(卓越班)专业在陕西录取分数线...
  10. angular中的装饰器 详解
  11. Eclipse+OpenCV3.1.0 的环境搭建
  12. Chrome的最小字体12px限制最终解决办法
  13. 百面机器学习(5)——非监督学习
  14. cl——long.py
  15. 最新版项目部署到腾讯云超详细教学
  16. AQI(空气质量指数)分析与预测(四)
  17. 6.计算机系统能力创新实践,计算机考核要重实践能力、培养创新精神
  18. 实现input框显示,但禁止输入
  19. konga--添加service和rouce详细步骤
  20. [CTF] 关于php代码审计的MD5类的练习

热门文章

  1. ALGO-146算法训练 4-2找公倍数
  2. PTA基础编程题目集6-4求自定类型元素的平均 (函数题)
  3. 网络工程 IP地址与子网掩码
  4. UML图中聚合、组合、关联、依赖、泛化的强弱关系
  5. jQuery 鼠标拖拽移动窗口
  6. Android PackageManagerService分析三:卸载APK
  7. Mac下MySQL卸载方法
  8. 动态规划解决约瑟夫环问题
  9. C++ 抛出和接收异常的顺序
  10. 使用win10 hyper-v安装linux系统