3

假设我有一个模型 App.Page、一个 App.Page 的 ArrayController 和一个 App.PageView 来渲染每个 App.Page。

我试图弄清楚如何最好地实现App.MyPagesView所以它的工作方式如下:

  • 如果App.showAllPages为真:我希望 MyPagesView 包含一个 App.PageView(s) 用于显示 App.pages 中的每个 App.Page
  • Else:我希望 MyPagesView 只显示一个 App.PageView,绑定到 App.pages.currentPage。

我想到的最直接的实现是使用这样的模板:

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

但这不会在用户每次打开和关闭showAllPages时为现有模型创建新视图吗?此外,当我尝试使用此模板时,我会收到有关性能问题的 emberJS 警告。

PageView(s) 的渲染可能非常复杂且昂贵。我真的很想为每个页面创建一次 PageView,并在不使用时从 DOM 中删除/隐藏不相关的 PageView。

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 }}

回顾一下,什么是正确的 EmberJS-y 方式来实现 MyPagesView 以便它响应App.showAllPages而无需在每次切换时重新创建所有视图?

它应该是某种 ContainerView 吗?或者我应该使用问题顶部显示的除非/否则模板吗?还是完全不同的东西?我觉得 EmberJS 中存在一个非常简单的解决方案,但它使我难以理解。

4

1 回答 1

2

这是我想出的最好的,封装为一个名为“CurrentCollectionView”的可重用视图类。我正在使用 CollectionView,并使用 view.set('isVisible') 来隐藏/显示适当的子视图。基本上像 CollectionView 一样使用它,但您可以将 currentContent 设置为隐藏除一个元素之外的所有内容,或者使用 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 回答