1

ページ内にパネルを作成する動的ウィジェット システムを作成しようとしています。例を 1 つ挙げてみましょう。

                Widgets.create({
                    name : 'menu-site',
                    title: 'Menu', 
                    content: 'This is my menu!'
                });  

これは次のようにレンダリングされます。

<section class="widget menu-site">
    <h1>Menu</h1>
    <article>This is my menu!</article>
</section>

大丈夫ですよね?私はそれを何千回もしました。ただし、内部でビューを使用しようとすると問題が発生します。

                var view = new MyCustomView;                  
                Widgets.create({
                    name : 'custom-panel',
                    title: 'Custom Panel', 
                    content: view.render().el
                });                    

WidgetView 内で outerHTML を呼び出してコンテンツをレンダリングできますが、それを行うと、MyCustomView 内で宣言されたイベントが機能しません!

誰かがこの問題に直面したことがありますか?

詳細が必要な人のために、これは私の WidgetView コードです:

        var Widget = Backbone.Model.extend({
            defaults : function() {
                return {
                    title : '',
                    content : '',
                    closeable : true
                }
            }
        });
        var WidgetList = Backbone.Collection.extend({
            url : '/widgets',
            model : Widget
        });
        Widgets = new WidgetList;


        var WidgetView = Backbone.View.extend({
            tagName : 'section',
            className : function() {
                return ['widget',' ', this.model.get('name')].join('');
            },
    template: _.template($('#widget-template').html()),

            events : {
                "click .close" : "removeWidget"
            },

            initialize : function() {
                this.listenTo(this.model, 'destroy', this.remove);
            },


            removeWidget  : function() {
                this.model.destroy();
            },

            render: function() {
              this.$el.append(this.template(this.model.toJSON()));   
              return this;
            },
        });

        var AppViewport = Backbone.View.extend({
            el : $("#widgets"),

            events : {
            },

            initialize : function() {
                this.listenTo(Widgets, 'add', this.addNewWidgetView);
            },

            addNewWidgetView : function(widget) {
              var view = new WidgetView({model: widget});
              this.$el.append(view.render().el);
            }
        });

        new AppViewport;

あるいは、これに対する別の回避策を考えています..しかし、この問題を理解するのに多くの時間を無駄にしたため、光が見えません!

更新 --------------- 18/01 ---------

いくつかのテストを行い、コードを変更しました。アンダースコア テンプレートを使用する代わりに、WidgetViewLayout を作成し、すべてのテンプレート作業を手動で行いました。

            var WidgetView = Backbone.View.extend({
                tagName : 'section',
                className : function() {
                    return ['widget',' ', this.model.get('name')].join('');
                },

                events : {
                    "click .close" : "removeWidget"
                },

                initialize : function() {
                    this.listenTo(this.model, 'destroy', this.remove);
                },


                removeWidget  : function() {
                    this.model.destroy();
                    MenuRouterInstance.navigate('');
                },

                render: function() {
                    var layout_view = new WidgetViewLayout({model: this.model.toJSON()});
                    this.$el.append(layout_view.render().el);   
                    return this;
                }
            });

            var WidgetViewLayout = Backbone.View.extend({
                tagName : 'div',

                render : function() {
                    var title = this.model.title,
                        content = this.model.content,
                        closeable = this.model.closeable || false;

                    var anchor = this.setupAnchor(closeable),
                        h1 = this.setupH1(title, anchor),
                        article = this.setupArticle(content);

                    this.$el.append(h1);
                    this.$el.append(article);

                    return this;
                },

                setupH1 : function(title, target) {
                    var element = $('<h1 />');
                    element.text(title);
                    element.append(target);   

                    return element;
                },

                setupAnchor : function(closeable) {
                    var element = '';
                    if(closeable == true) {
                        element = $('<a />'); 
                        element.addClass('close');
                        element.text('(fechar)');
                    }

                    return element;
                },

                setupArticle : function(content) {
                    var element = $('<article />');
                    element.append(content);

                    return element;
                }
            })

現在は機能しているようですが、ウィジェット内で作成されたビューにはまだ問題があります。

                    var view = new MyView;                  
                    Widgets.create({
                        name : 'menu',
                        title: 'My menu', 
                        content: view.render().el
                    }); 

MyView が内部に複数の SubView を作成し、model.destroy を呼び出して Subview の Model の 1 つを削除すると、リッスンされたメソッド「this.remove」は、1 つだけを削除するのではなく、すべての SubView を削除してしまいます。最後に、私はこれを行うことを余儀なくされました:

                removeit : function(removed_item) {
                    if(removed_item.get('name') == this.model.get('name')) {
                        this.remove();                            
                    }
                },

悪いパターンかどうかはわかりませんが、うまくいきました!誰かがより良いアイデアを持っていれば幸いです!

][`,s

4

1 に答える 1

3

あなたの問題は、DOM 要素オブジェクト ( el) を文字列として扱おうとしていることにあると思います。これを行う場合:

content: view.render().el

ライブ DOM ノードがcontentあり、ビューのイベントはその DOM ノードにバインドされます。outerHTMLテンプレートを介してノードのHTMLを取得するためにHTMLメソッドの1つを使用できますが(明らかにあなたの場合) delegate、イベントを処理するのは、最終的に作業するHTMLの文字列ではなく、DOMノードにバインドされます。

必要に応じて、生の DOM ノードをそのまま使用するように少し変更できますrender。たとえば、次のようになります。

render: function() {
    var json = this.model.toJSON();
    if(_(json.content).isString()) {
        this.$el.append(this.template(json));
    }
    else {
        var content = json.content;
        delete json.content;
        this.$el.append(this.template(json));
        this.$('article').append(content);
    }
}

基本的に、content文字列でない場合は$el、テンプレートを使用するのではなく、手動で入力します。

于 2013-01-16T03:15:49.777 に答える