Backbone.js事件高级用法 #

一、事件命名空间 #

1.1 命名约定 #

javascript
obj.on('user:created', function() {});
obj.on('user:updated', function() {});
obj.on('user:deleted', function() {});

obj.on('order:created', function() {});
obj.on('order:updated', function() {});

1.2 层级命名 #

javascript
obj.on('app:init', function() {});
obj.on('app:user:login', function() {});
obj.on('app:user:logout', function() {});
obj.on('app:data:sync', function() {});

1.3 状态命名 #

javascript
obj.on('model:before:save', function() {});
obj.on('model:save:success', function() {});
obj.on('model:save:error', function() {});

obj.on('view:before:render', function() {});
obj.on('view:render', function() {});
obj.on('view:after:render', function() {});

二、事件代理 #

2.1 集合代理模型事件 #

javascript
var users = new Backbone.Collection();

users.on('change:name', function(model, name) {
    console.log('用户姓名变化:', name);
});

var user = users.add({ name: '张三' });
user.set('name', '李四');

2.2 自定义事件代理 #

javascript
var EventProxy = {
    proxyEvents: function(source, events, prefix) {
        var self = this;
        
        events.split(' ').forEach(function(event) {
            self.listenTo(source, event, function() {
                var args = [prefix + ':' + event].concat(
                    Array.prototype.slice.call(arguments)
                );
                self.trigger.apply(self, args);
            });
        });
    }
};

var ChildView = Backbone.View.extend({
    initialize: function() {
        _.extend(this, EventProxy);
        this.proxyEvents(this.model, 'change destroy', 'model');
    }
});

var view = new ChildView({ model: model });

view.on('model:change', function() {
    console.log('模型变化');
});

2.3 事件转发 #

javascript
var EventForwarder = {
    forward: function(target, events) {
        var self = this;
        
        events.split(' ').forEach(function(event) {
            self.on(event, function() {
                var args = [event].concat(Array.prototype.slice.call(arguments));
                target.trigger.apply(target, args);
            });
        });
    }
};

var source = _.extend({}, Backbone.Events, EventForwarder);
var target = _.extend({}, Backbone.Events);

source.forward(target, 'alert warning error');

target.on('alert', function(msg) {
    console.log('转发收到:', msg);
});

source.trigger('alert', 'Hello');

三、事件队列 #

3.1 批量触发 #

javascript
var EventEmitter = _.extend({
    queue: [],
    processing: false,
    
    queueEvent: function(event) {
        var args = Array.prototype.slice.call(arguments);
        this.queue.push(args);
        
        if (!this.processing) {
            this.processQueue();
        }
    },
    
    processQueue: function() {
        if (this.queue.length === 0) {
            this.processing = false;
            return;
        }
        
        this.processing = true;
        var args = this.queue.shift();
        this.trigger.apply(this, args);
        
        this.processQueue();
    }
}, Backbone.Events);

3.2 延迟触发 #

javascript
var DelayedEmitter = _.extend({
    delayedTriggers: {},
    
    triggerDelayed: function(event, delay) {
        var self = this;
        var args = Array.prototype.slice.call(arguments, 2);
        
        if (this.delayedTriggers[event]) {
            clearTimeout(this.delayedTriggers[event]);
        }
        
        this.delayedTriggers[event] = setTimeout(function() {
            self.trigger.apply(self, [event].concat(args));
            delete self.delayedTriggers[event];
        }, delay);
    }
}, Backbone.Events);

3.3 防抖触发 #

javascript
var DebouncedEmitter = _.extend({
    debouncedTriggers: {},
    
    triggerDebounced: function(event, wait) {
        var self = this;
        var args = Array.prototype.slice.call(arguments, 2);
        
        if (!this.debouncedTriggers[event]) {
            this.debouncedTriggers[event] = _.debounce(function() {
                self.trigger.apply(self, [event].concat(args));
            }, wait);
        }
        
        this.debouncedTriggers[event]();
    }
}, Backbone.Events);

四、事件拦截 #

4.1 前置拦截 #

javascript
var InterceptableEvents = _.extend({
    interceptors: {},
    
    before: function(event, interceptor) {
        if (!this.interceptors[event]) {
            this.interceptors[event] = { before: [], after: [] };
        }
        this.interceptors[event].before.push(interceptor);
    },
    
    trigger: function(event) {
        var interceptors = this.interceptors[event];
        var args = Array.prototype.slice.call(arguments, 1);
        
        if (interceptors && interceptors.before.length > 0) {
            for (var i = 0; i < interceptors.before.length; i++) {
                if (interceptors.before[i].apply(this, args) === false) {
                    return this;
                }
            }
        }
        
        return Backbone.Events.trigger.apply(this, arguments);
    }
}, Backbone.Events);

InterceptableEvents.before('save', function(data) {
    if (!data.valid) {
        console.log('拦截无效数据');
        return false;
    }
});

InterceptableEvents.on('save', function(data) {
    console.log('保存数据:', data);
});

InterceptableEvents.trigger('save', { valid: false });
InterceptableEvents.trigger('save', { valid: true, name: '张三' });

4.2 后置处理 #

javascript
var PostProcessEvents = _.extend({
    processors: {},
    
    after: function(event, processor) {
        if (!this.processors[event]) {
            this.processors[event] = [];
        }
        this.processors[event].push(processor);
    },
    
    trigger: function(event) {
        var result = Backbone.Events.trigger.apply(this, arguments);
        
        var processors = this.processors[event];
        if (processors && processors.length > 0) {
            var args = Array.prototype.slice.call(arguments, 1);
            processors.forEach(function(processor) {
                processor.apply(this, args);
            });
        }
        
        return result;
    }
}, Backbone.Events);

五、事件调试 #

5.1 事件日志 #

javascript
var DebugEvents = _.extend({
    debug: false,
    
    enableDebug: function() {
        this.debug = true;
    },
    
    disableDebug: function() {
        this.debug = false;
    },
    
    trigger: function(event) {
        if (this.debug) {
            console.log('[Event]', event, Array.prototype.slice.call(arguments, 1));
        }
        return Backbone.Events.trigger.apply(this, arguments);
    }
}, Backbone.Events);

5.2 事件追踪 #

javascript
var EventTracker = _.extend({
    history: [],
    maxHistory: 100,
    
    track: function(event) {
        this.history.push({
            event: event,
            args: Array.prototype.slice.call(arguments, 1),
            timestamp: Date.now()
        });
        
        if (this.history.length > this.maxHistory) {
            this.history.shift();
        }
    },
    
    getHistory: function() {
        return this.history;
    },
    
    getLast: function(n) {
        return this.history.slice(-n);
    }
}, Backbone.Events);

EventTracker.on('all', function(event) {
    EventTracker.track.apply(EventTracker, arguments);
});

5.3 事件统计 #

javascript
var EventStats = _.extend({
    stats: {},
    
    record: function(event) {
        if (!this.stats[event]) {
            this.stats[event] = { count: 0, lastTriggered: null };
        }
        
        this.stats[event].count++;
        this.stats[event].lastTriggered = Date.now();
    },
    
    getStats: function() {
        return this.stats;
    },
    
    getEventCount: function(event) {
        return this.stats[event] ? this.stats[event].count : 0;
    }
}, Backbone.Events);

EventStats.on('all', function(event) {
    EventStats.record(event);
});

六、实用示例 #

6.1 事件中间件 #

javascript
var MiddlewareEvents = _.extend({
    middlewares: [],
    
    use: function(middleware) {
        this.middlewares.push(middleware);
    },
    
    trigger: function(event) {
        var args = Array.prototype.slice.call(arguments);
        var self = this;
        var index = 0;
        
        function next() {
            if (index < self.middlewares.length) {
                var middleware = self.middlewares[index++];
                middleware.call(self, args, next);
            } else {
                Backbone.Events.trigger.apply(self, args);
            }
        }
        
        next();
    }
}, Backbone.Events);

MiddlewareEvents.use(function(args, next) {
    console.log('中间件1:', args);
    next();
});

MiddlewareEvents.use(function(args, next) {
    console.log('中间件2:', args);
    next();
});

MiddlewareEvents.trigger('custom', 'data');

6.2 事件订阅管理 #

javascript
var SubscriptionManager = {
    subscriptions: {},
    
    subscribe: function(obj, event, callback, context) {
        var id = _.uniqueId('sub_');
        
        this.subscriptions[id] = {
            obj: obj,
            event: event,
            callback: callback,
            context: context
        };
        
        obj.on(event, callback, context);
        
        return id;
    },
    
    unsubscribe: function(id) {
        var sub = this.subscriptions[id];
        
        if (sub) {
            sub.obj.off(sub.event, sub.callback, sub.context);
            delete this.subscriptions[id];
        }
    },
    
    unsubscribeAll: function() {
        for (var id in this.subscriptions) {
            this.unsubscribe(id);
        }
    }
};

6.3 条件事件 #

javascript
var ConditionalEvents = _.extend({
    conditions: {},
    
    onWhen: function(event, condition, callback, context) {
        var self = this;
        
        this.on(event, function() {
            if (condition.call(context || self)) {
                callback.apply(context || self, arguments);
            }
        }, context);
    },
    
    setCondition: function(name, condition) {
        this.conditions[name] = condition;
    }
}, Backbone.Events);

ConditionalEvents.setCondition('isLoggedIn', function() {
    return !!localStorage.getItem('token');
});

ConditionalEvents.onWhen('action', function() {
    return this.conditions.isLoggedIn();
}, function() {
    console.log('已登录用户执行操作');
});

七、总结 #

7.1 高级技巧 #

技巧 说明
命名空间 组织事件结构
事件代理 代理其他对象事件
事件拦截 控制事件触发流程
事件调试 追踪和调试事件

7.2 最佳实践 #

  1. 使用命名空间组织事件
  2. 合理使用事件代理
  3. 实现事件拦截器控制流程
  4. 添加调试支持便于排查问题
  5. 注意事件性能,避免过度使用
最后更新:2026-03-28