• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >jquery > jQuery技巧之让任何组件都支持类似DOM的事件管理

jQuery技巧之让任何组件都支持类似DOM的事件管理

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了jquery组件,dom事件管理等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

本文介绍一个jquery的小技巧,能让任意组件对象都能支持类似DOM的事件管理,也就是说除了派发事件,添加或删除事件监听器,还能支持事件冒泡,阻止事件默认行为等等。在jquery的帮助下,使用这个方法来管理普通对象的事件就跟管理DOM对象的事件一模一样,虽然在最后当你看到这个小技巧的具体内容时,你可能会觉得原来如此或者不过如此,但是我觉得如果能把普通的发布-订阅模式的实现改成DOM类似的事件机制,那开发出来的组件一定会有更大的灵活性和扩展性,而且我也是第一次使用这种方法(见识太浅的原因),觉得它的使用价值还蛮大的,所以就把它分享出来了。

在正式介绍这个技巧之前,得先说一下我之前考虑的一种方法,也就是发布-订阅模式,看看它能解决什么问题以及它存在的问题。

1. 发布-订阅模式

很多博客包括书本上都说javascript要实现组件的自定义事件的话,可以采用发布-订阅模式,起初我也是坚定不移地这么认为的,于是用jquery的$.Callbacks写了一个:

define(function(require, exports, module) {
var $ = require('jquery');
var Class = require('./class');
function isFunc(f) {
return Object.prototype.toString.apply(f) === '[object Function]';
}
/**
* 这个基类可以让普通的类具备事件驱动的能力
* 提供类似jq的on off trigger方法,不考虑one方法,也不考虑命名空间
* 举例:
* var e = new EventBase();
* e.on('load', function(){
* console.log('loaded');
* });
* e.trigger('load');//loaded
* e.off('load');
*/
var EventBase = Class({
instanceMembers: {
init: function () {
this.events = {};
//把$.Callbacks的flag设置成一个实例属性,以便子类可以覆盖
this.CALLBACKS_FLAG = 'unique';
},
on: function (type, callback) {
type = $.trim(type);
//如果type或者callback参数无效则不处理
if (!(type && isFunc(callback))) return;
var event = this.events[type];
if (!event) {
//定义一个新的jq队列,且该队列不能添加重复的回调
event = this.events[type] = $.Callbacks(this.CALLBACKS_FLAG);
}
//把callback添加到这个队列中,这个队列可以通过type来访问
event.add(callback);
},
off: function (type, callback) {
type = $.trim(type);
if (!type) return;
var event = this.events[type];
if (!event) return;
if (isFunc(callback)) {
//如果同时传递type跟callback,则将callback从type对应的队列中移除
event.remove(callback);
} else {
//否则就移除整个type对应的队列
delete this.events[type];
}
},
trigger: function () {
var args = [].slice.apply(arguments),
type = args[0];//第一个参数转为type
type = $.trim(type);
if (!type) return;
var event = this.events[type];
if (!event) return;
//用剩下的参数来触发type对应的回调
//同时把回调的上下文设置成当前实例
event.fireWith(this, args.slice(1));
}
}
});
return EventBase;
});

(基于seajs以及《详解Javascript的继承实现》介绍的继承库class.js)

只要任何组件继承这个EventBase,就能继承它提供的on off trigger方法来完成消息的订阅,发布和取消订阅功能,比如我下面想要实现的这个FileUploadBaseView:

define(function(require, exports, module) {
var $ = require('jquery');
var Class = require('./class');
var EventBase = require('./eventBase');
var DEFAULTS = {
data: [], //要展示的数据列表,列表元素必须是object类型的,如[{url: 'xxx.png'},{url: 'yyyy.png'}]
sizeLimit: 0, //用来限制BaseView中的展示的元素个数,为0表示不限制
readonly: false, //用来控制BaseView中的元素是否允许增加和删除
onBeforeRender: $.noop, //对应beforeRender事件,在render方法调用前触发
onRender: $.noop, //对应render事件,在render方法调用后触发
onBeforeAppend: $.noop, //对应beforeAppend事件,在append方法调用前触发
onAppend: $.noop, //对应append事件,在append方法调用后触发
onBeforeRemove: $.noop, //对应beforeRemove事件,在remove方法调用前触发
onRemove: $.noop //对应remove事件,在remove方法调用后触发
};
/**
* 数据解析,给每个元素的添加一个唯一标识_uuid,方便查找
*/
function resolveData(ctx, data){
var time = new Date().getTime();
return $.map(data, function(d){
d._uuid = '_uuid' + time + Math.floor(Math.random() * 100000);
});
}
var FileUploadBaseView = Class({
instanceMembers: {
init: function (options) {
this.base();
this.options = this.getOptions(options);
},
getOptions: function(options) {
return $.extend({}, DEFAULTS, options);
},
render: function(){
},
append: function(data){
},
remove: function(prop){
}
},
extend: EventBase
});
return FileUploadBaseView;
});

实际调用测试如下:



测试中,实例化了一个FileUploadBaseView对象f,并设置了它的name属性,通过on方法添加一个跟hello相关的监听器,最后通过trigger方法触发了hello的监听器,并传递了额外的两个参数,在监听器内部除了可以通过监听器的函数参数访问到trigger传递过来的数据,还能通过this访问f对象。

从目前的结果来说,这个方式看起来还不错,但是在我想要继续实现FileUploadBaseView的时候碰到了问题。你看我在设计这个组件的时候那几个订阅相关的option:

 

我原本的设计是:这些订阅都是成对定义,一对订阅跟某个实例方法对应,比如带before的那个订阅会在相应的实例方法(render)调用前触发,不带before的那个订阅会在相应的实例方法(render)调用后触发,而且还要求带before的那个订阅如果返回false,就不执行相应的实例方法以及后面的订阅。最后这个设计要求是考虑到在调用组件的实例方法之前,有可能因为一些特殊的原因,必须得取消当前实例方法的调用,比如调用remove方法时有的数据不能remove,那么就可以在before订阅里面做一些校验,能删除的返回true,不能删除的返回false,然后在实例方法中触发before的订阅后加一个判断就可以了,类似下面的这种做法:

但是这个做法只能在单纯的回调函数模式里实现,在发布-订阅模式下是行不通的,因为回调函数只会跟一个函数引用相关,而发布-订阅模式里,同一个消息可能有多个订阅,如果把这种做法应用到发布-订阅里面,当调用this.trigger('beforeRender')的时候,会把跟beforeRender关联的所有订阅全部调用一次,那么以哪个订阅的返回值为准呢?也许你会说可以用队列中的最后一个订阅的返回值为准,在大多数情况下也许这么干没问题,但是当我们把“以队列最后的一个订阅返回值作为判断标准”这个逻辑加入到EventBase中的时候,会出现一个很大的风险,就是外部在使用的时候,一定得清楚地管理好订阅的顺序,一定要把那个跟校验等一些特殊逻辑相关的订阅放在最后面才行,而这种跟语法、编译没有关系,对编码顺序有要求的开发方式会给软件带来比较大的安全隐患,谁能保证任何时候任何场景都能控制好订阅的顺序呢,更何况公司里面可能还有些后来的新人,压根不知道你写的东西还有这样的限制。

解决这个问题的完美方式,就是像DOM对象的事件那样,在消息发布的时候,不是简简单单的发布一个消息字符串,而是把这个消息封装成一个对象,这个对象会传递给它所有的订阅,哪个订阅里觉得应该阻止这个消息发布之后的逻辑,只要调用这个消息的preventDefault()方法,然后在外部发布完消息后,调用消息的isDefaultPrevented()方法判断一下即可:

而这个做法跟使用jquery管理DOM对象的事件是一样的思路,比如bootstrap的大部分组件以及我在前面一些博客中写的组件都是用的这个方法来增加额外的判断逻辑,比如bootstrap的alert组件在close方法执行的时候有一段这样的判断:

按照这个思路去改造EventBase是一个解决问题的方法,但是jquery的一个小技巧,能够让我们把整个普通对象的事件管理变得更加简单,下面就让我们来瞧一瞧它的庐山真面目。

2. jquery小技巧模式

1)技巧一

如果在定义组件的时候,这个组件是跟DOM对象有关联的,比如下面这种形式:

那么我们可以完全给这个组件添加on off trigger one这几个常用事件管理的方法,然后将这些方法代理到$element的相应方法上:

通过代理,当调用组件的on方法时,其实调用的是$element的on方法,这样的话这种类型的组件就

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • jQuery技巧之让任何组件都支持类似DOM的事件管理
  • 不定义JQuery插件 不要说会JQuery
  • jQuery进行组件开发完整实例

相关文章

  • jQuery动态生成表格及右键菜单功能示例
  • jQuery插件开发全解析
  • jQuery实现QQ空间汉字转拼音功能示例
  • 基于jquery的分页控件(C#)
  • jQuery实现的仿select功能代码
  • 更高效的使用JQuery 这里总结了8个小技巧
  • jQuery插件slick实现响应式移动端幻灯片图片切换特效
  • jQuery实现二维码扫描功能
  • jQuery制作仿Mac Lion OS滚动条效果
  • jquery仿搜索自动联想功能代码

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • jquery中EasyUI实现同步树
    • JQuery datepicker 用法详解
    • jquery实现简单的banner轮播效果【实例】
    • 十个迅速提升JQuery性能让你的JQuery跑得更快
    • 由简入繁实现Jquery树状结构的方法(推荐)
    • jQuery+Ajax+PHP+Mysql实现分页显示数据实例讲解
    • jQuery实现个性翻牌效果导航菜单的方法
    • jQuery 版本的文本输入框检查器Input Check
    • datagrid框架的删除添加与修改
    • jquery 圆形旋转图片滚动切换效果

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有