我正在使用 Backbone 开发一个应用程序,并且遇到了动态创建“el”属性的 View 问题 <g>
元素。 View 的代码如下:
var DependencyLineView = Backbone.View.extend({
//el: document.createElementNS(nameSpace, 'g'),
initialize: function () {
//var gElement = document.createElementNS(nameSpace, 'g');
//var gElementComplete = createShape(this.options.iteration, this.el);
var gElement = document.createElementNS(nameSpace, 'g');
var gElementComplete = createShape(this.options.iteration, gElement);
this.el = gElementComplete;
$(gElementComplete).attr('stroke-width', '1px')
.attr('stroke', 'red')
.attr('fill', 'red');
this.el = gElementComplete;
this.render();
},
render: function() {
$('#lineContainer').append(this.el);
},
events: {
"click": "clickEvent",
},
clickEvent: function(ev) {
alert('here');
},
});
如果我在初始化期间生成元素(而不是使用“el”属性),则渲染将按预期进行(即,每次证实并渲染新 View 时,<g>
元素都会添加到 #lineContainer)。但是,如果我使用“el”属性生成元素,则只有一个 <g>
无论我添加新 View 并渲染多少次,都会创建元素。我出于演示目的编写了一个名为“createShape”的函数,它添加了一些 <line>
元素到 SVG 组元素。以下是这两种方法的结果:
初始化期间生成元素:
<svg id="lineContainer">
<g stroke-width="1px" stroke="red">
<line x1="10" y1="10" x2="50" y2="10"></line>
<line x1="50" y1="10" x2="50" y2="50"></line>
<line x1="50" y1="50" x2="100" y2="50"></line>
</g>
<g stroke-width="1px" stroke="red">
<line x1="20" y1="20" x2="100" y2="20"></line>
<line x1="100" y1="20" x2="100" y2="100"></line>
<line x1="100" y1="100" x2="200" y2="100"></line>
</g>
</svg>
使用“el”属性生成:
<svg id="lineContainer">
<g stroke-width="1px" stroke="red" fill="red">
<line x1="0" y1="0" x2="0" y2="0"></line>
<line x1="0" y1="0" x2="0" y2="0"></line>
<line x1="0" y1="0" x2="0" y2="0"></line>
<line x1="10" y1="10" x2="50" y2="10"></line>
<line x1="50" y1="10" x2="50" y2="50"></line>
<line x1="50" y1="50" x2="100" y2="50"></line>
<line x1="20" y1="20" x2="100" y2="20"></line>
<line x1="100" y1="20" x2="100" y2="100"></line>
<line x1="100" y1="100" x2="200" y2="100"></line>
<line x1="30" y1="30" x2="150" y2="30"></line>
<line x1="150" y1="30" x2="150" y2="150"></line>
<line x1="150" y1="150" x2="300" y2="150"></line>
<line x1="40" y1="40" x2="200" y2="40"></line>
<line x1="200" y1="40" x2="200" y2="200"></line>
<line x1="200" y1="200" x2="400" y2="200"></line>
</g>
</svg>
我希望能够利用“el”属性动态生成 SVG 组元素,以便我可以本地使用主干委托(delegate)的事件(并且出于许多其他原因,如果不仅仅是为了遵守主干样式) JavaScript 编码),但每个组都需要单独附加(而不是像示例中那样折叠)。我做错了什么?
JSFiddle:http://jsfiddle.net/e2DJ8/1/
最佳答案
当你在你的观点中这样说时:
el: document.createElementNS(nameSpace, 'g'),
您正在附加 <g>
到el
在 View 的原型(prototype)中,因此所有实例共享一个 <g>
当然,直到您更改 el
里面initialize
。但是,在分配新的 el
之前,你正在这样做:
initialize: function () {
var gElementComplete = createShape(this.options.iteration, this.el);
// --------------------------------------------------------^^^^^^^
您的createShape
函数会将内容添加到其第二个参数中,并且每次创建新的 DependencyLineView
时,他们使用完全相同的 <g>
作为他们的el
当您调用createShape
时:没有明显的 el
对于 View 的每个实例,它们都共享完全相同的 <g>
.
确实没有理由指定 el
创建 View “类”时,不必费心,只需创建 <g>
根据需要并使用 setElement
将其附加到 View :
initialize: function (options) {
var gElement = document.createElementNS(nameSpace, 'g');
var gElementComplete = createShape(options.iteration, gElement);
// ...
this.setElement(gElementComplete);
演示:http://jsfiddle.net/ambiguous/zVfJb/
请注意,我正在使用 setElement
而不是直接分配给this.el
,永远不要分配给 this.el
你自己,因为这不会绑定(bind)事件处理程序或设置缓存 this.$el
。另请注意,我没有使用 Backbone 0.3.3,因为这是 Backbone 的石器时代版本,我假设您至少使用 1.0。使用更新的 Backbone 还意味着 this.options
不会在 View 中自动设置,所以我只是使用 options.iteration
和一个明确的 options
initialize
的参数.
如果出于某种原因您坚持拥有 el
在 View 定义中然后将其设为一个函数,以便每个实例都有一个不同的 <g>
:
el: function() {
return document.createElementNS(nameSpace, 'g');
}
演示:http://jsfiddle.net/ambiguous/GLbts/
也就是说,所有这些渲染逻辑确实应该位于 View 的 render
内。方法(这就是 render
的用途,渲染); render
通常也以 return this;
结尾所以你也应该这样做。那么理想情况下你会这样说:
var i, var v;
for(i = 0; i < 5; ++i) {
v = new DependencyLineView({ iteration: i });
$('#lineContainer').append(v.render().el); // this is why `render` returns `this`.
}
并且你的 View 根本不会接触 DOM:它只会创建它需要的元素,然后由调用者将它们放置在某个地方。
关于javascript - 带有 SVG <g> 元素的主干 View 无法正确渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20831350/