2

我已经在 SO 上查看了所有 Backbone.js 答案,但找不到解决我的问题的答案;如果我错过了一个,请指出我。

我正在尝试获取 BackBone.js 子视图来呈现包含在其父视图呈现的 HTML 中的静态元素。我已经创建了我能说明的最简单的例子。这是HTML:

<!DOCTYPE html>
<html>
<head>
  <title>Child View Not Rendering</title>
</head>
<body>
  <div id="parent"></div>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.js"></script>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore.js"></script>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone.js"></script>
  <script src="test.js"></script>
</body>
</html>

这是test.jsJavascript:

(function () {
  var Child = Backbone.View.extend({
    el: '#child',
    render: function () {
      this.$el.html('World');
    }
  });
  var Parent = Backbone.View.extend({
    el: '#parent',
    initialize: function () {
      this.child = new Child();
    },
    render: function () {
      this.$el.html('Hello <span id="child"></span>!');
      this.child.render();
    }
  });
  var parent = new Parent();
  parent.render();
})();

当它运行时,我只看到"Hello !"而不是"Hello World!"在浏览器中看到。我究竟做错了什么?提前致谢。

更新

我找到了自己的答案(请参阅下面的“答案”),但现在我仍然想知道我的解决方案是否是最好的方法,或者我是否仍然不应该在其中创建new Child()Parent.initialize()弄清楚如何让它Child.$el像使用jQuery.live(). 想法?

更新#2

new Child()我找到了另一个留下in创建的答案Parent.initialize() (请参阅下面我的“答案”中的更新)。它需要使用 jQuery 来分配.$el属性并从中重新分配.el属性,Child.render()但感觉就像是 hack。我再问,有没有更好的办法?

更新#3

我能够找到一种更简洁的方式来分配.$el财产;.setElement(); 请在下面的答案中查看我的更新 #2。并且还在寻找更好的方法。

更新#4

找到了一种方法来创建一个封装丑陋的“父”类,尽管它不能与其他链接组合;.constructor()在下面的答案中查看我的更新#3。我仍然想找到一个需要最少代码来扩展视图的混合策略。所以这就是我将这个问题留待解决的问题;有人有很好的答案吗?提前致谢。

更新#5

从这里开始更新#4;它会导致一系列问题。**因此,如果有人可以解决这些问题并将其作为一个不需要大量代码来混入的可行混入,我会很乐意为他们提供选定的答案。提前致谢。

4

2 回答 2

1

发生这种情况是因为子元素只是在内存中呈现,从未添加到 DOM 中。您有#child作为子视图的元素,但这不在 HTML 中。因此,您可以将 HTML 更改为:

<div id="parent"></div>
<div id="child"></div>

这会将“世界”放入 DOM 中,在 #child..

但是,我假设因为它们被命名为父子节点,所以您实际上希望它们嵌套在这种情况下,父节点将负责渲染子节点。如果是这样,请将您的子视图更改为:

var Child = Backbone.View.extend({
    id: 'child',
    render: function () {
        this.$el.html('World');
        return this;
    }
});

这将删除“el”选择器并添加“id”属性,因为这是动态创建的。其次,渲染方法返回 this 是因为:“一个好的约定是在渲染结束时返回 this 以启用链式调用。” - 骨干文档。

然后在您的父视图中,您可以调用:

this.$el.append(this.child.render().el);

它将子元素渲染到内存中,然后将其添加到父 div 内的 DOM 中。

于 2013-07-26T17:02:25.890 回答
1

啊哈!我找到了自己的解决方案。似乎 for 的值'#child'Child.el丢弃了,new Child()因为当时 DOM 中不存在 ID。因此,通过this.child = new Child();Parent.initialize()到移动,Parent.render()我能够使其工作。

"Hello World!"这是在浏览器中显示的有效 Javascript :

(function () {
  var Child = Backbone.View.extend({
    el: '#child',
    render: function () {
      this.$el.html('World');
    }
  });
  var Parent = Backbone.View.extend({
    el: '#parent',
    initialize: function () {
    },
    render: function () {
      this.$el.html('Hello <span id="child"></span>!');
      this.child = new Child();
      this.child.render();
    }
  });
  var parent = new Parent();
  parent.render();
})();

更新

我找到了另一个解决方案,但感觉就像一个真正的黑客。这次我将创建的内容new Child()移回Parent.initialize()Child.initialize(). 我在实际渲染之前添加了以下代码,它分配了.$el属性并从中重新分配了.el属性:

this.$el = $("#child");
this.el = this.$el[0];

我还添加了@Ian Routledge提醒我应该使用的return this;每个。.render()

这是完整更新的 Javascript 代码:

(function () {
  var Child = Backbone.View.extend({
    render: function () {
      this.$el = $("#child");
      this.el = this.$el[0];
      this.$el.html('World');
      return this;
    }
  });
  var Parent = Backbone.View.extend({
    el: '#parent',
    initialize: function () {
      this.child = new Child();
    },
    render: function () {
      this.$el.html('Hello <span id="child"></span>!');
      this.child.render();
      return this;
    }
  });
  var parent = new Parent();
  parent.render();
})();

不确定我将使用哪种解决方案,但很高兴知道如何让它们都工作。

更新#2

好吧,我在 Backbone.js 方面的经验不足表明了这一点。有一种更清洁的方法可以完成上述操作。代替:

this.$el = $("#child");
this.el = this.$el[0];

我们可以使用这个:

this.setElement('#child', false);

完整更新的 Javascript 代码在这里:

(function () {
  var Child = Backbone.View.extend({
    render: function () {
      this.setElement('#child', false);
      this.$el.html('World');
      return this;
    }
  });
  var Parent = Backbone.View.extend({
    el: '#parent',
    initialize: function () {
      this.child = new Child();
    },
    render: function () {
      this.$el.html('Hello <span id="child"></span>!');
      this.child.render();
      return this;
    }
  });
  var parent = new Parent();
  parent.render();
})();

更新#3

一个(希望是)最后的更新:我能够隔离这些骇人听闻的代码并进入一个我称为DynamicChildView. 我添加了自己的.constructor()保存this.elthis.render,设置.render()为一个函数,该函数重置.el/.$el然后调用孩子的.render(),然后最后调用隐式构造函数Backbone.View

这是最新的 Javascript 代码:

(function () {

  var DynamicChildView = Backbone.View.extend({
    constructor: function(attributes,options) {
      this._childEl = this.el;
      this._childRender = this.render;
      this.render = function () {
        this.el = this.el || this._childEl;
        this.setElement(_.result(this, 'el'), false);
        this._childRender();
        return this;
      };
      Backbone.View.prototype.constructor.apply(this,attributes,options);
    }
  });

  var Child = DynamicChildView.extend({
    el: "#child",
    render: function () {
      this.$el.html('World');
      return this;
    }
  });

  var Parent = Backbone.View.extend({
    el: '#parent',
    initialize: function () {
      this.child = new Child();
    },
    render: function () {
      this.$el.html('Hello <span id="child"></span>!');
      this.child.render();
      return this;
    }
  });
  var parent = new Parent();
  parent.render();
})();

这种方法可能更好,但不能与覆盖构造函数的其他扩展组合。我想弄清楚如何使它成为一个不需要大量代码即可包含在新视图中的 mixin,但这可能是我今天必须投入的所有时间。

更新#4

在我上面的答案中划掉更新#3中的解决方案;它会导致各种问题。回到这个答案的UPDATE #2

于 2013-07-26T17:04:20.637 回答