如何在每个Marionette视图渲染上记录消息?

joe*_*ews 1 javascript backbone.js marionette

我有一个具有大量视图的Marionette应用程序.我想在每个渲染时将调试消息记录到控制台(并且可能在将来,在其他事件上)

我目前通过从每个View的onRender方法记录来执行此操作:

MyModule.MyViewType = Marionette.ItemView.extend({
    // ... view properties and methods

    onRender: function() {
      // ... other onRender code
      console.debug('MyModule.MyViewType %s %s', this.cid, 'render');
    }
});
Run Code Online (Sandbox Code Playgroud)

这有效,但它有几个缺点:

  • 必须手动将日志记录代码添加到每个视图.
  • 有几个视图没有自定义onRender操作,因此我只是为了调试而添加方法.那感觉不对.
  • 如果我想完全改变或删除日志记录方法(例如,去生产),我需要改变很多代码.
  • 如果我想为另一个事件添加代码,例如show,我需要为每个视图添加一个事件处理程序或一个新方法.

有没有办法记录每个View渲染而不向每个View添加代码?

joe*_*ews 5

是.您可以修饰 Backbone.View.constructor以挂钩View创建生命周期.然后,您可以在所有View实例上为任何事件注册回调.

!function() {
  // Development: log view renders and other events
  // Don't execute this function in production.


  // Save a reference to the original Backbone.View and create a new type
  // that replaces the constructor method
  var OriginalView = Backbone.View,
      LoggingView = OriginalView.extend({
        constructor: function() {

          // Execute the original constructor first
          OriginalView.apply(this, arguments);

          // Allow views to define a `type` property to clarify log messages
          var type = this.type || 'Unknown View Type',
              cid = this.cid;

          // Bind to Marionette.View's `render` event (and any other events)
          this.listenTo(this, 'render', function(e,b) {
            console.debug('%s %s - %s', type, cid, 'render');
          });
        }
      });

  // Replace Backbone.View with our decorated view
  Backbone.View = LoggingView;
}();
Run Code Online (Sandbox Code Playgroud)

要记录视图类型,请在View实现中添加一个属性:

MyModule.MyViewType = Marionette.ItemView.extend({
    type: 'MyModule.MyViewType',
    // ... rest of the view code
});
Run Code Online (Sandbox Code Playgroud)

可靠地确定JavaScript的对象"类型"(构造函数名称)是有问题的,因此添加此属性是确定正在呈现的视图类型的最佳方法.

通过提供要记录的事件数组,可以轻松地将此答案推广到多个事件类型:

var events = ['render', 'show', 'beforeClose'];

events.forEach(function(eventType) {
  this.listenTo(this, eventType, function() {
    console.debug('%s %s - %s', type, cid, eventType)
  });
}).bind(this);
Run Code Online (Sandbox Code Playgroud)

示例输出:

Projects.ViewType1 view13 - render 
Projects.ViewType2 view3 - render 
Projects.ViewType3 view6 - render 
Projects.ViewType4 view9 - render 
Projects.ViewType4 view17 - render
Projects.ViewType4 view19 - render 
Projects.ViewType2 view3 - render
Run Code Online (Sandbox Code Playgroud)

这种方法解决了问题中描述的所有问题 - 有少量代码,视图不需要直接更改,并且可以省略单个函数调用以删除生产代码中的日志记录.

这种方法特定于Marionette - 因为vanilla Backbone的render方法是用户定义的,没有相应的render事件.

有关扩展Backbone构造函数方法的更多详细信息,请参阅Derick Bailey的博客.