4

構築中のアプリにバックボーンを使用しています。このアプリには、内部に他の 2 つのビューを含むテンプレートをレンダリングするマスター ビューがあります。1 つのヘッダー ビューと、コンテンツを含む別のビュー。ヘッダー ビューは、コンテンツ ビューとやり取りするためだけに使用され、特定の機能も備えています。

ヘッダー テンプレートとコンテンツ テンプレートには同じコードがあり、ajax 呼び出しが行われたときに表示されるローダー イメージを含む非表示の DIV があります。私が抱えている問題は、アプリを初めてロードするとき (またはコンテンツ ビューを更新するとき) に、コンテンツ ビューが ajax 要求からいくつかのデータをロードしているが、ヘッダーとコンテンツの両方にローダーが表示されていることです。テンプレート (ajaxStart() がビューにアタッチされていないグローバル イベントであった場合など)。

コンテンツ ビューの設定は次のとおりです。

App.View.Content = Backbone.View.extend({
        type:'test',
        template: twig({
            href: '/js/app/Template/Content.html.twig',
            async: false
        }),
        block:{
            test:twig({
                href: '/js/app/Template/block/test.html.twig',
                async: false
            })
        },
        list:[],

        showLoader: function(el){
            console.log('loader: ', $('#ajax_loader', el));
            $('#ajax_loader', el).show();
            console.log('Ajax request started...');
        },

        hideLoader: function(el){
            $('#ajax_loader', el).hide();
            console.log('Ajax request ended...');
        },

        initialize: function(params)
        {
            this.el   = params.el;
            this.type = params.type || this.type;
            var self  = this;

            this.el
                .ajaxStart(function(){self.showLoader(self.el);})
                .ajaxStop(function(){self.hideLoader(self.el);});

            this.render(function(){
                self.list = new App.Collection.ListCollection();
                self.refresh(1, 10);
            });
        },

    refresh:function(page, limit)
    {
        var self = this;
        console.log('Refreshing...');

        $('#id-list-content').fadeOut('fast', function(){
            $(this).html('');
        });

        this.list.type  = this.type;
        this.list.page  = page || 1;
        this.list.limit = limit || 10;

        this.list.fetch({
            success: function(data){
                //console.log(data.toJSON());

                $.each(data.toJSON(), function(){
                    //console.log(this.type);
                    var tpl_block = self.block[this.type];
                    if (tpl_block != undefined) {
                        var block = tpl_block.render({
                            test: this
                        });
                        $(block).appendTo('#id-list-content');
                    }
                });

                $('#id-list-content').fadeIn('fast');
            }
        });
    },

    render: function(callback)
    {
        console.log('Rendering list...');
        this.el.html(this.template.render({

        }));

        if (undefined != callback) {
            callback();
        }
    }
});

ご覧のとおり、見苦しいコードを使用して ajaxStart / ajaxStop イベントをアタッチしています。

this.el
    .ajaxStart(function(){self.showLoader(self.el);})
    .ajaxStop(function(){self.hideLoader(self.el);});

私はそれを次のように持っていました:

this.el
    .ajaxStart(self.showLoader())
    .ajaxStop(self.hideLoader());

しかし、何らかの理由で、私の側ではまだ未定義であり、 andthis.elで定義されていませんでした。showLoader()hideLoader()

とDOMに接続されていて、このビューだけがそれをリッスンできると考えていましたajaxStart()。しかし、まったく同じ設定 (ロードされた twig テンプレートを除く) を持つ私の headerView は、どうやらイベントを受け取り、ローダーを表示します。ajaxStop()this.el

この動作を確認するために、コンテンツ ビューで をコメント アウトしましたshowLoader()が、ローダーは引き続きヘッダー ビューに表示されます。

何が間違っているのかわかりません:(

編集(「mu is too short」からの回答後):

私のコンテンツビューは次のようになります。

showLoader: function(){
            //this.$('#ajax_loader').show();
            console.log('Ajax request started...');
        },

        hideLoader: function(){
            this.$('#ajax_loader').hide();
            console.log('Ajax request ended...');
        },

        initialize: function(params)
        {
            var self  = this;

            console.log(this.el);

            _.bindAll(this, 'showLoader', 'hideLoader');

            this.$el
                .ajaxStart(this.showLoader)
                .ajaxStop(this.hideLoader);

            this.render(function(){
                self.list = new App.Collection.List();
                self.refresh(1, 10);
            });
        },
...

render: function(callback)
        {
            console.log('Rendering post by page...');
            this.$el.html(this.template.render({

            }));

            if (undefined != callback) {
                callback();
            }
}

そして私のヘッダービュー:

...
showLoader: function(){
            this.$('#ajax_loader').show();
            //console.log('Ajax request started...');
        },

        hideLoader: function(el){
            this.$('#ajax_loader').hide();
            console.log('Ajax request ended...');
        },

        initialize: function(params)
        {
            var self = this;
            _.bindAll(this, 'showLoader', 'hideLoader');

            this.$el
                .ajaxStart(this.showLoader)
                .ajaxStop(this.hideLoader);

            this.models.Link = new App.Model.Link();
            this.render();
        },

        render: function(callback)
        {
            this.$el.html(this.template.render({
                data: []
            }));

            if (undefined != callback) {
                callback();
            }
        }
...

しかし、ローダーはまだヘッダービューテンプレートに表示されています

PS:this.showLoader()現在のバックボーン ビュー内で関数を呼び出したかったため、タイプミスではありませんでした。

4

1 に答える 1

3

JavaScript 関数のコンテキスト (AKA this) は、関数が定義されているコンテキストではなく、関数の呼び出し方法に依存します。このようなものを考えると:

var f = o.m;
f();

o.mプレーンな関数を介して呼び出すとfthis内部o.mは通常グローバル コンテキスト (windowブラウザー内) になります。applyと を使用しcallて別のものを選択することもできますthis

f.call(o);

あなたが期待するものをthis作るでしょう。oほとんどの JavaScript 環境で強制的にthis使用することができますbindが、あまり脇道にそれないようにしたいと思います。

ポイントは、次のことです。

this.el
    .ajaxStart(this.showLoader)
    .ajaxStop(this.hideLoader);

showLoaderそれを保証するには十分ではなくhideLoader、適切なコンテキストで実行されます。また、あなたが最後に持っていた括弧は単なるタイプミスだったshowLoaderと思います。hideLoader

バックボーン アプリケーションでコンテキストを強制する最も一般的な方法は、以下を使用すること_.bindAllですinitialize

initialize: function(params) {
    _.bindAll(this, 'showLoader', 'hideLoader');
    //...

this.showLoaderこれは基本的に andthis.hideLoaderを、ラッパーとほぼ同等のものに置き換えます。

function() { self.showLoader(self.el) }

それが整ったら_.bindAll、これは:

this.el
    .ajaxStart(this.showLoader)
    .ajaxStop(this.hideLoader);

うまくいきます。


ところで、これを行う必要はありません:

this.el = params.el;

あなたの中initializeで、バックボーンはあなたのためにそれを行います:

コンストラクター/初期化 new View([options])

[...] 渡された場合、ビューに直接アタッチされる特別なオプションがいくつかあります: modelcollectionelid、および。classNametagNameattributes

そして、次のようなことをする必要はありません:

$('#ajax_loader', el).show();

いずれかの場合、バックボーンは、引数リストの最後にあるを隠すことなく同じことを行う$メソッドをビューに提供します。elこのようにします:

this.$('#ajax_loader').show();

バックボーンではより慣用的です。

さらに、this.el必ずしも jQuery オブジェクトであるとは限らないため、これを行わないでください。

this.el.html(this.template.render({ ... }));

あなたのでは、代わりrenderにキャッシュされたものを使用してください:this.$el

this.$el.html(this.template.render({ ... }));
于 2012-08-27T08:59:48.803 に答える