【问题标题】:Connecting predefined HTML to Models and Views in Backbone将预定义的 HTML 连接到 Backbone 中的模型和视图
【发布时间】:2013-07-15 07:24:25
【问题描述】:

我是从 Backbone.js 开始的,所以我必须说我对这些概念还不是很熟悉。

我已经预定义了 HTML,我想使用 Backbone 来管理它。这很重要,我想保持这种状态。

说这是我的 HTML 的(部分):

<div class="pig" data-id="1">
    <h1>Harry</h1>
    <input type="text" value="Harry">
</div>
<div class="pig" data-id="2">
    <h1>Jill</h1>
    <input type="text" value="Jill">
</div>
<div class="pig" data-id="3">
    <h1>Bob</h1>
    <input type="text" value="Bob">
</div>

现在的想法是,当您更改输入时,这应该会更新我的主干模型并渲染视图,从而使用新名称更新 h1。我不确定应该如何设置模型和视图。

我的模型和视图的结构有点像,但我不知道应该如何使用它们。

目前我有这样的事情:

var PigModel = Backbone.Model.extend()
var pigs = new PigModel()
pigs.reset([
    {"id": "1", "name": "Harry"},
    {"id": "2", "name": "Jill"},
    {"id": "3", "name": "Bob"}
])

var PigView = Backbone.View.extend({
    el: '.pig',
    events: {
        'change input': function() {
            // update appropriate Model ?
            this.render()
        }
    },
    render: function() {

        var new_name = // get new name from model ?

        var pig_template = _.template($('#pig_template').html())
        var new_contents = pig_template({ name: new_name })

        // render only the pig that was changed ?

    }
})

所以在我在代码中添加 cmets 的地方我不知道该怎么做:

  • change 事件中,如何找到属于该视图的模型?我可以遍历所有模型,但这似乎效率低下。
  • 再次在render方法中,如何获取属于该视图的模型?
  • 在render方法中,如何只渲染事件所在的猪视图,而不渲染所有的猪?

也许我在这里采取了完全错误的方法。如果是这样,请指出正确的方向。

【问题讨论】:

  • Backbone 不能这样工作。您可以使用视图的initialize 函数中的大量代码来破解它,但实际上您需要在视图中呈现 HTML,而不是使用预呈现的 HTML。 Backbone 的全部意义在于分离模型的显示和模型本身
  • @Bojangles 我实际上找到了一种非常干净的方法来做到这一点。看我的回答。

标签: javascript html backbone.js


【解决方案1】:

好的,我设法弄明白了。

这个想法是使用 jQuery 遍历现有的 HTML,然后使用 jquery 选择器和预加载的 json 创建视图和模型的实例。

HTML:

<div class="pig">
    <h1>Harry</h1>
    <input type="text" value="Harry" />
</div>
<div class="pig">
    <h1>Jill</h1>
    <input type="text" value="Jill" />
</div>
<div class="pig">
    <h1>Bob</h1>
    <input type="text" value="Bob" />
</div>

Javascript:

$(function() {

    var PigModel = Backbone.Model.extend()

    var PigView = Backbone.View.extend({
        events: {
            'change input': function(e) {
                this.model.set('name', e.currentTarget.value)
                this.render()
            }
        },
        render: function() {
            this.$el.html(
                '<h1>' + this.model.get('name') + '</h1>' +
                '<input type="text" value="' + this.model.get('name') + '" />'
            )
        }
    })

    var pig_data = [
        {"name": "Harry"},
        {"name": "Jill"},
        {"name": "Bob"}
    ]


    // the magic starts here

    var pig_number = 0

    $('.pig').each(function() {

        new PigView({
            el: this,
            model: new PigModel(pig_data[pig_number])
        })

    })

})

Jsfiddle:http://jsfiddle.net/tU3Mt/1/

像这样,我可以从服务器提供一个完整的 HTML 页面,然后将所需的元素加载到我的主干视图/模型中并从那里管理它们。

关于是否应该使用骨干网: 从开发人员的角度来看,这可能不是最合乎逻辑/最有效的方法。但是,我认为这种方法有一些重要的好处:

  • 客户端获取的 HTML 直接提供,无需处理任何 javascript 即可呈现页面。随着您的 HTML 变得更大/更复杂,这将变得更加明显。
  • 搜索引擎/网络爬虫可以读取您的网页,因为它提供完整的 HTML。

对于某些人来说,这些点可能并不那么重要,因为 web 应用程序在加载后会很快,并且搜索引擎不必抓取它。然而,在某些情况下,您可能会同时使用网站和 web 应用程序,其中页面需要快速加载、可抓取,但也有一个足够复杂的响应式界面,以使开发人员想要使用诸如骨干网之类的东西。如果有人对此有其他想法,我当然想听听。

【讨论】:

    【解决方案2】:

    附加到现有的 html 是可能的,但这不是很常见的方法。因此,几乎没有关于此的真实信息:(

    您可以尝试按照以下文章中描述的步骤操作:http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-2-progressive-enhancement-with-backbone-js/

    想法是,在渲染的 html 中添加一些数据属性,这样您就可以将模型与渲染的 html 匹配。

    【讨论】:

    • 我实际上找到了一种非常干净的方法来做我想做的事。看我的回答。
    【解决方案3】:

    我会采取一些不同的方法。创建Pig 模型的集合。有一个知道如何渲染一头猪的视图,PigView。让它负责更新一头猪,对应h1。拥有一个更高级别的视图,可以将猪的集合呈现到您想要的任何父元素中。

    var PigModel = Backbone.Model.extend()
    // You want a collection of pig models
    var pigs = new Backbone.Collection([
        {"id": "1", "name": "Harry"},
        {"id": "2", "name": "Jill"},
        {"id": "3", "name": "Bob"}
    ], {model: PigModel});
    
    var PigView = Backbone.View.extend({
        // Want to set the class for the generated el not pass a selector
        className : "pig",
        // Dummy template from your markup in question
        template : function (modelAttrs) {
            return "<h1>"+modelAttrs.name+"</h1><input type='text' value='"+modelAttrs.name+"'>";
        },
        events: {
            'change input': function(e) {
                // You have a reference to the model through this
                this.model.set({name : e.currentTarget.value});
                this.render();
            }
        },
        // Bare bones render
        render: function() {
            this.$el.html(this.template(this.model.attributes));
            return this;
        }
    });
    
    // Parent view for responsible for rendering the collection of pigs somewhere.
    var HigherLevelView = Backbone.View.extend({
        render : function () {
            pigs.each(function (pig) {
                this.$el.append(new PigView({model : pig}).render().el);
            });
        }
    });
    
    $("body").append(new HigherLevelView().render().el);
    

    Fiddle

    【讨论】:

    • 好的,我理解你的方法,但我有现有的 HTML,我想将我的 Backbone 视图挂钩。所以我不希望 Backbone 在我的页面第一次加载时渲染任何东西。我的页面第一次加载 HTML 时已经在服务器端呈现。然后当客户端加载时,我想在某些事件上开始使用 Backbone 更改我的 DOM。
    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    相关资源
    最近更新 更多