SVG <g>元素无法正确呈现的骨干视图</g>

时间:2013-12-29 23:38:59

标签: javascript jquery html backbone.js svg

我正在使用Backbone处理一个应用程序,并且我遇到的问题是“el”属性是动态创建的<g>元素。视图的代码如下:

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”属性),则按预期进行渲染(I.E.每次新视图得到证实和渲染时,<g>元素都会添加到#lineContainer中。但是,如果我使用“el”属性生成元素,则无论添加新视图并渲染多少次,都只会创建一个<g>元素。我为了演示目的编写了一个名为“createShape”的函数,它为SVG组元素添加了一些<line>元素。以下是两种方法的结果:

在初始化期间生成元素:

<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组元素,这样我就可以使用骨干本地委派的事件(并且由于其他原因,如果不仅仅是为了坚持骨干风格在JavaScript中编码)但每个组需要单独附加(不折叠,就像它在示例中所做的那样)。我做错了什么?

JSFiddle:http://jsfiddle.net/e2DJ8/1/

1 个答案:

答案 0 :(得分:3)

当你在你的观点中这样说时:

el: document.createElementNS(nameSpace, 'g'),

您将<g>附加到视图原型中的el,以便所有实例共享一个<g>,直到您更改el为止在initialize内。但是,在分配新的el之前,您要这样做:

initialize: function () {
    var gElementComplete = createShape(this.options.iteration, this.el);
    // --------------------------------------------------------^^^^^^^

您的createShape函数会在其第二个参数中添加内容,每次创建新DependencyLineView时,它们都会使用与<g>完全相同的el您致电createShape:视图的每个实例都没有明确的el,它们都分享完全相同的<g>

创建视图“类”时没有理由指定el,所以不要打扰,只需根据需要创建<g>并使用setElement将其附加到视图中:

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,因为它不会绑定事件处理程序或设置缓存的this.$el 1}}。另请注意,我没有使用Backbone 0.3.3,因为这是Backbone的石器时代版本,我假设您使用的是至少1.0。使用更新的Backbone还意味着this.options不会自动在视图中设置,因此我只使用options.iterationoptions initialize个参数。

如果由于某种原因你坚持在视图定义中使用el,那么将它作为一个函数,以便每个实例都有一个不同的<g>

el: function() {
    return document.createElementNS(nameSpace, 'g');
}

演示:http://jsfiddle.net/ambiguous/GLbts/

也就是说,所有这些渲染逻辑都应该在你的视图的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`.
}

并且您的视图根本不会触及DOM:它只会创建所需的元素,并将其留给调用者将它们放在某处。