如何将此单击处理程序分配给DOM元素?

时间:2013-09-11 01:59:25

标签: javascript jquery backbone.js

现在我对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调用,在“x”标签处更新DOM,其中包含来自v对象的“el”属性的内容(在调用render之后) 。如果先前没有设置“el”属性,这种技术应该将内容呈现到DOM中,并且如果它具有先前从render方法写入的有效内容,则它是“未附加的div”。

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

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

2 个答案:

答案 0 :(得分: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是   string,传递给$(),取第一个匹配的元素,然后   重新分配给el。否则,从id创建一个元素,   className和tagName属性。 http://backbonejs.org/docs/backbone.html#section-133

既然我们知道this.el的来源,请查看events docs,看看它是如何处理的。

视图在main.js

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

修改

  

其中没有一个解释了如何设置View对象的EL属性   以及点击触发器的工作原理。

我会尝试更好地解释它:

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

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

此时,我们留下了this.el,其中包含所有必需的标记,并设置了所有事件侦听器。但是,this.el仍然不是DOM的一部分。

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

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

答案 1 :(得分: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