3

モデル App.Page、App.Page の ArrayController、および各 App.Page をレンダリングするための App.PageView があるとします。

App.MyPagesViewを最適に実装する方法を見つけようとしているので、次のように機能します。

  • App.showAllPagesが true の場合: MyPagesView に、App.pages の各 App.Page を表示するための App.PageView(s) を含めたい
  • Else : MyPagesView に、App.pages.currentPage にバインドされた 1 つの App.PageView のみを表示したい。

私が思いつく最も簡単な実装は、次のようなテンプレートを使用することです。

// MyPagesViewApproach1
{{#unless App.showAllPages}}
    {{view App.PageView pageBinding="pages.currentPage"}}
{{else}}
    {{#each pages}}
        {{view App.PageView pageBinding="this"}}
    {{/each}}
{{/unless}}

しかし、これでは、ユーザーがshowAllPagesのオンとオフを切り替えるたびに、既存のモデルの新しいビューが作成されませんか? また、このテンプレートを使用しようとすると、パフォーマンスの問題に関する emberJS の警告が表示されます。

PageView は非常に複雑で、レンダリングにコストがかかる可能性があります。ページごとに一度 PageView を作成し、使用していないときに無関係な PageView を DOM から削除/非表示にするだけです。

App = Ember.Application.create({
    showAllPages: false,
    pages: Ember.ArrayController.create({
        content: []
        currentPage: null
    }),
    ready: function () {
        this.pages.pushObject(App.Page.create({title: 'Page One'});
        this.pages.pushObject(App.Page.create({title: 'Some Other Page'});
        this.pages.pushObject(App.Page.create({title: 'Grrreatest Page Evar'});
        this.pagesController.set('currentPage',
            this.pagesController.get('firstObject'));
    }
});
App.Page = Ember.Object.extend({
    title: null
    // etc, etc...
});
App.PageView = Ember.View.extend({
    templateName: 'page',
    page: null    // should be bound to an App.Page
});

App.MyPagesView_Approach1 = Ember.View.extend({
    pagesBinding: 'Elicitation.pages'
    // ???
});
App.MyPagesView_Approach2 = Ember.ContainerView.extend({
    // ???
});

そして私のHTML:

<script type="text/x-handlebars" data-template-name="page">
    The title of this page is {{ page.title }}
</script>

{{view App.MyPagesView }}

要約すると、トグルされるたびにすべてのビューを再作成せずにApp.showAllPagesに応答するように MyPagesView を実装する適切な EmberJS-y の方法は何ですか?

ある種の ContainerView である必要がありますか? または、質問の上部に表示されている until/else テンプレートを使用する必要がありますか? それともまったく違うもの?EmberJS には本当に単純な解決策が存在するように感じますが、それは私にはわかりません。

4

1 に答える 1

2

これは、「CurrentCollectionView」と呼ばれる再利用可能な View クラスとしてカプセル化された、私が思いついた最高のものです。CollectionView を使用しており、view.set('isVisible') を使用して適切な子ビューを非表示/表示しています。基本的に CollectionView のように使用しますが、currentContent を設定してコンテンツの 1 つの要素を除くすべてを非表示にしたり、showAllContent を使用して currentContent をオーバーライドしたりできます。

App.CurrentCollectionView = Ember.CollectionView.extend({
    showAllContent: false,
    currentContent: null,

    currentContentChanged: function () {
        console.log("Elicitation.PagesView.currentContentChanged()");
        var showAllContent = this.get('showAllContent');

        if (Ember.none(showAllContent) || !showAllContent) {
            var contents = this.get('content');
            var currentContent = this.get('currentContent');
            this.get('childViews').forEach(function (view, i) {
                var isVisible = contents.objectAt(i) == currentContent;
                view.set('isVisible', isVisible);
            });
        } else {
            this.get('childViews').forEach(function (view) {
                view.set('isVisible', true);
            });
        }
    }.observes('currentContent', 'showAllContent', 'childViews')
});

CurrentCollectionView を使用して MyPagesView を実装する例:

App.MyPagesView = App.CurrentCollectionView.extend({
    itemViewClass: App.PageView,
    contentBinding: 'App.pages',
    currentContentBinding: 'App.pages.currentPage',
    showAllContentBinding: 'App.showAllPages',
});

または、テンプレートとしてインラインで使用する場合:

{{view App.CurrentCollectionView itemViewClass="App.PageView" contentBinding="App.pages" currentContentBinding="App.pages.currentPage" showAllContentBinding="App.showAllPages"}}

他の誰かがこれを便利だと思ったり、改善できることを願っています (お願いします!)

于 2012-05-25T00:01:12.697 に答える