1

现在我对 Backbone 有了更好的了解(我希望),我一直在用细齿梳浏览这个应用程序,以了解它是如何工作的:

https://github.com/ccoenraets/nodecellar/tree/master/public

让我难过的最新事情是 windetails.js 中的 EL 标签(这里:https ://github.com/ccoenraets/nodecellar/blob/master/public/js/views/winedetails.js )

我将在下面粘贴相关代码,但我的问题是如何分配此视图的 EL 属性?正如您将在视图定义中注意到的那样,没有定义 EL 标记,也没有分配 idTag 或 className 属性。但是,我在 firebug 中验证了该视图确实在侦听 DOM 中间的 DIV 标签(实际上就在内容 DIV 的下方)。那么它是如何附着在那里的呢?如果不是这样,Click 处理程序将无法正常工作,但确实如此。之前所有看起来都是以相同方式创建的视图都具有未附加的 EL 属性。

window.WineView = Backbone.View.extend({

    initialize: function () {
        this.render();
    },

    render: function () {
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    },

    events: {
        "change" : "change",
        "click .save" : "beforeSave",
        "click .delete" : "deleteWine",
        "drop #picture" : "dropHandler"
    },

    change: function (event) {
        // Remove any existing alert message
        utils.hideAlert();

        // Apply the change to the model
        var target = event.target;
        var change = {};
        change[target.name] = target.value;
        this.model.set(change);

        // Run validation rule (if any) on changed item
        var check = this.model.validateItem(target.id);
        if (check.isValid === false) {
            utils.addValidationError(target.id, check.message);
        } else {
            utils.removeValidationError(target.id);
        }
    },

    beforeSave: function () {
        var self = this;
        var check = this.model.validateAll();
        if (check.isValid === false) {
            utils.displayValidationErrors(check.messages);
            return false;
        }
        this.saveWine();
        return false;
    },

    saveWine: function () {
        var self = this;
        console.log('before save');
        this.model.save(null, {
            success: function (model) {
                self.render();
                app.navigate('wines/' + model.id, false);
                utils.showAlert('Success!', 'Wine saved successfully', 'alert-success');
            },
            error: function () {
                utils.showAlert('Error', 'An error occurred while trying to delete this item', 'alert-error');
            }
        });
    },

    deleteWine: function () {
        this.model.destroy({
            success: function () {
                alert('Wine deleted successfully');
                window.history.back();
            }
        });
        return false;
    },

    dropHandler: function (event) {
        event.stopPropagation();
        event.preventDefault();
        var e = event.originalEvent;
        e.dataTransfer.dropEffect = 'copy';
        this.pictureFile = e.dataTransfer.files[0];

        // Read the image file from the local file system and display it in the img tag
        var reader = new FileReader();
        reader.onloadend = function () {
            $('#picture').attr('src', reader.result);
        };
        reader.readAsDataURL(this.pictureFile);
    }

});

编辑 有很多关于这种模式的讨论: $(x).append(v.render().el)

如果我错了,有人纠正我,但据我所知,这是一个 Jquery 调用,用于使用 v 对象的“el”属性的内容更新“x”标记处的 DOM(在调用 render 之后)。即使之前没有设置“el”属性并且是“未附加的 div”,只要它之前从渲染方法写入了有效内容,这种技术也应该将内容呈现到 DOM 中。

然而,在将内容写入 DOM 之后,“el”属性仍然是一个未附加的 div,直到它被直接分配给 DOM。

我通过 Firebug 验证了这个 Backbone 应用程序有两个视图,它们都以这种方式呈现,并且都具有未附加的 div el 属性。这些是 wineList 视图和 homeView。但是,第三个视图是 WineDetail 视图,它似乎没有未附加的 EL 属性。它的 EL 属性似乎已附加,而且还有助于点击事件。我的问题是这个 EL 属性是如何附加并分配给 DOM 的?

4

2 回答 2

1

通过查看内部结构可以找到答案Backbone.View

查看构造函数:

  var View = Backbone.View = function(options) {
    this.cid = _.uniqueId('view');
    this._configure(options || {});
    //this function is responsible for the creation of the `this.el` property.
    this._ensureElement();
    this.initialize.apply(this, arguments);
    this.delegateEvents();
  };

确保 View 有一个要渲染的 DOM 元素。如果 this.el 是一个字符串,则通过 $() 传递它,获取第一个匹配元素,并将其重新分配给 el。否则,从 id、className 和 tagName 属性创建一个元素。http://backbonejs.org/docs/backbone.html#section-133

既然我们知道了this.el来自哪里,请查看事件文档以了解它是如何处理的。

视图在main.js中实例化

$('#content').html(new WineView({model: wine}).el);

编辑:

这些都没有解释 View Object 的 EL 属性是如何设置的,以及点击触发器是如何工作的。

我将尝试更好地解释它:

this.elthis._ensureElement由构造函数中的调用创建Backbone.View。我们还可以看到它this.render是从initialize在实例化时运行的函数调用的。我们可以看到,在 中this.render,我们将 的内容设置this.el为应用于this.template模型的结果。

现在,在 a 的初始化过程中Backbone.View,在this.initialize被调用之后,events通过调用this.delegateEvents. 这是使用给定选择器附加事件侦听器的地方。请注意,大多数事件将直接附加到this.el并使用事件委托,而不是将事件直接附加到子元素上。

在这一点上,我们留下了一个this.el包含所有必要标记并设置了所有事件侦听器的。但是,this.el它仍然不是 DOM 的一部分。

但从代码中,我们可以看到,在视图实例化后,this.el它将作为元素的子元素附加到 DOM :#content

$('#content').html(new WineView({model: wine}).el);
于 2013-09-11T02:19:19.313 回答
0

这段代码的最后三行:

events: {
    "change" : "change",
    "click .save" : "beforeSave",
    "click .delete" : "deleteWine",
    "drop #picture" : "dropHandler"
},

看起来像这种模式(查看事件结构中的第二行):

"click" = event to register a handler for
".save" = selector to use for selecting objects for the event handler
beforeSave = method to call when the event fires
于 2013-09-11T02:58:15.493 回答