javascript - 带有 SVG <g> 元素的主干 View 无法正确渲染

标签 javascript jquery html backbone.js svg

我正在使用 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/

相关文章:

javascript - 使用 javascript 函数在 <div> 内渲染 HTML 表格

javascript - 如何动态更改 Firefox 附加组件的页面 worker 的 ContentURL?

javascript - 如何使用ajax方法交叉检查数据库中是否存在数据?

javascript - 即使设备锁定也继续播放 iframe

javascript - Angular js Bootstrap 按钮禁用

php - jquery向多个选择下拉列表添加属性

javascript - 想要隐藏 javascript 表单提交上的参数吗?

html - 表单帖子中字段的大小限制是多少?

asp.net - .Net 转发器中 div 的 CSS

php - 尝试在第一个字母更改时在按字母顺序排序的列表中添加分隔符