使用 Ember 进行导航的正确方法

Posted

技术标签:

【中文标题】使用 Ember 进行导航的正确方法【英文标题】:Right way to do navigation with Ember 【发布时间】:2012-07-04 08:05:25 【问题描述】:

导航侧边栏的“正确方式”(或者至少是选项,如果没有单一的“Ember 方式”)是什么?我应该以某种方式查看 ContainerViews,还是应该只使用新的 outlet 功能并将导航粘贴在我的应用程序视图中?

此外,根据 URL(我正在使用路由)在 li 上设置 .active 类的“正确方法”是什么?有什么帮手吗?

【问题讨论】:

【参考方案1】:

由于最近路由器 API 发生变化,前面的示例不再有效,因此我不会修复这些问题。所有使用旧路由器的应用程序都应尽快迁移到最新版本。

这是一个更新的小提琴: Source | Live Demo

我会经常维护/修复/添加功能。

2013 年 4 月 3 日编辑

替代样品 - WIP:source | demo

以下所有内容均已弃用

2012 年 11 月 9 日

只是将链接添加到更好的样本,该样本也在选中定向路由时在当前导航栏项中设置op在当前纳维栏项中设置类的一部分

来源JSFiddle(点击here查看运行)

如果您查看 NavigationController,您会看到“selected”属性,我用它来检查子视图 NavigationItemView 的 isActive 方法。 isActive 将根据同一视图(在模板中定义)的menu 属性中的值和(控制器的)属性selected 中的值返回真或假。然后检查 classNameBinding 表达式,该表达式将“活动”设置为该特定孩子的类或不设置任何内容。 还要检查我将导航项标记为选中的 ConnectOutlets。

这是在ember-latest 上运行的。 我还使用了一些 Ember.Bootstrap 以及一些原始的 Twitter Bootstrap 功能/类/等(但我已将样式替换为 metro-bootstrap)。

由于空间和所有的原因,这里没有粘贴整个内容。我将保留原始代码和链接以供参考原始问题/答案。

我会继续更新这个新示例,因为 ember 很有趣 =)

更新>

This fiddle 从视图中显示静态导航栏,outlet 仅用于内容显示,也可以直接进入显示到see it running

如您所见,您可以使用包含您的操作链接的简单视图,并在您的应用程序主视图中呈现此视图。 “开始”下的子路线也有一个迷你导航栏,来自类似的模板。

车把

<script type="text/x-handlebars" data-template-name="application">
    <h1>My Ember Application</h1>
    view App.NavbarView controllerBinding="controller.controllers.navbarController"
    <br /><hr />
    <div class="content">
        outlet
    </div>
</script>

<script type="text/x-handlebars" data-template-name="navbar">
    <ul>
        <li><a href="#" action gotoHome>Home</a></li>
        <li><a href="#" action gotoStarting>Getting Started</a></li>
        <li><a href="#" action gotoCommunity>Community</a></li>
    </ul>
</script>

<script type="text/x-handlebars" data-template-name="getting-started-menu">
    <ul>
        <li><a href="#" action gotoIndex>Overview</a></li>
        <li><a href="#" action gotoMVC>About MVC</a></li>
        <li><a href="#" action gotoEmber>About Ember</a></li>
    </ul>
</script>
    
<script type="text/x-handlebars" data-template-name="home">
    <h2>Welcome</h2>
    <br />
    <img src="http://emberjs.com/images/about/ember-productivity-sm.png"  />
    <br />
    <br />
    <p>Bacon ipsum dolor sit amet qui ullamco exercitation, shankle beef sed bacon ground round kielbasa in. Prosciutto pig bresaola, qui meatloaf ea tongue non dolore et pork belly andouille ribeye spare ribs enim. Enim exercitation elit, brisket nisi ex swine in jerky consequat pastrami dolore sed ad. In drumstick cow, salami swine fatback short ribs ham ut in shankle consequat corned beef id. Deserunt prosciutto beef speck. Sirloin incididunt kielbasa excepteur irure.</p>
    <p>Do beef ribs dolore swine chicken shankle, venison officia qui magna ea anim. Jerky shank shankle, tongue in pork loin commodo boudin elit cupidatat turducken id capicola meatball. Strip steak ham hock tenderloin, id chicken drumstick sint jerky. Dolore veniam cillum minim, pariatur est beef. Sunt fatback tri-tip ex chuck.</p>
    <br />
    <br />
    <strong>Note</strong>: This is a basic template with no <i>bindings</i>
</script>

<script type="text/x-handlebars" data-template-name="starting">
    <h2>Getting Started with Ember</h2>
    view App.StartingMenuView
    <br />
    <br />
    <br />
    <p>Bacon ipsum dolor sit amet qui ullamco exercitation, shankle beef sed bacon ground round kielbasa in. Prosciutto pig bresaola, qui meatloaf ea tongue non dolore et pork belly andouille ribeye spare ribs enim. Enim exercitation elit, brisket nisi ex swine in jerky consequat pastrami dolore sed ad. In drumstick cow, salami swine fatback short ribs ham ut in shankle consequat corned beef id. Deserunt prosciutto beef speck. Sirloin incididunt kielbasa excepteur irure.</p>
    <p>Do beef ribs dolore swine chicken shankle, venison officia qui magna ea anim. Jerky shank shankle, tongue in pork loin commodo boudin elit cupidatat turducken id capicola meatball. Strip steak ham hock tenderloin, id chicken drumstick sint jerky. Dolore veniam cillum minim, pariatur est beef. Sunt fatback tri-tip ex chuck.</p>
    <br />
    <br />
    <strong>Note</strong>: This is a basic template has a menu view embedded
</script>

<script type="text/x-handlebars" data-template-name="about-mvc">
    <h2>About MVC</h2>
    view App.StartingMenuView
    <br /><br />
    <br /><p>
        Model–View–Controller (MVC) is a software design for interactive computer user interfaces that separates the representation of  information from the user's interaction with it.[1][8] The model consists of application data and business rules, and the controller mediates input, converting it to commands for the model or view.[3] A view can be any output representation of data, such as a chart or a diagram. Multiple views of the same data are possible, such as a pie chart for management and a tabular view for accountants.
    </p>
    Read more at <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" target="_blank">Wikipedia</a>
    <br />
    <br />
    <strong>Note</strong>: This is a basic template has a menu view embedded
</script>

<script type="text/x-handlebars" data-template-name="about-ember">
    <h2>About Ember</h2>
    view App.StartingMenuView
    <br /><br />
    <br />
    <p>A framework for creating <strong>ambitious</strong> web applications</p>
    Read more at <a href="http://emberjs.com/about/" target="_blank">emberjs.com</a>
    <br />
    <br />
    <p>Bacon ipsum dolor sit amet qui ullamco exercitation, shankle beef sed bacon ground round kielbasa in. Prosciutto pig bresaola, qui meatloaf ea tongue non dolore et pork belly andouille ribeye spare ribs enim. Enim exercitation elit, brisket nisi ex swine in jerky consequat pastrami dolore sed ad. In drumstick cow, salami swine fatback short ribs ham ut in shankle consequat corned beef id. Deserunt prosciutto beef speck. Sirloin incididunt kielbasa excepteur irure.</p>
    <p>Do beef ribs dolore swine chicken shankle, venison officia qui magna ea anim. Jerky shank shankle, tongue in pork loin commodo boudin elit cupidatat turducken id capicola meatball. Strip steak ham hock tenderloin, id chicken drumstick sint jerky. Dolore veniam cillum minim, pariatur est beef. Sunt fatback tri-tip ex chuck.</p><br />
    <br />
    <strong>Note</strong>: This is a basic template has a menu view embedded
</script>

<script type="text/x-handlebars" data-template-name="community">
    <h1>Ember Community</h1>
    <p>
        Get in touch with the community
    </p>
    <p>Featured contact info:</p>
    #each item in content
        <a bindAttr href="item.linkUrl"  target="_blank">
            <img   bindAttr src="item.imageUrl" title="item.displayName"  /><br />
            item.displayName
        </a><br />
    /each
    <br />
    Check more information about ember community at <a href="http://emberjs.com/community/" target="_blank">emberjs.com</a>
    <br />
    <br />
    <strong>Note</strong>: This is a template with a <i>foreach</i> type of loop
</script>​

JavaScript

App = Em.Application.create();

App.ApplicationController = Em.Controller.extend();
App.ApplicationView = Em.View.extend(
    templateName: 'application'
);

App.HomeController = Em.Controller.extend();
App.HomeView = Em.View.extend(
    templateName: 'home'
);

App.NavbarController = Em.Controller.extend();
App.NavbarView = Em.View.extend(
    templateName: 'navbar'
);

App.StartingController = Em.Controller.extend();
App.StartingView = Em.View.extend(
    templateName: 'starting'
);


App.StartingMenuController = Em.Controller.extend();
App.StartingMenuView = Em.View.extend(
    templateName: 'getting-started-menu'
);

App.AboutMVCController = Em.Controller.extend();
App.AboutMVCView = Em.View.extend(
    templateName: 'about-mvc'
);

App.AboutEmberController = Em.Controller.extend();
App.AboutEmberView = Em.View.extend(
    templateName: 'about-ember'
);

App.CommunityModel = Em.Object.extend(
    displayName: null,
    linkUrl: null,
    imageUrl: null
);

App.CommunityController = Em.ArrayController.extend(
    content: [],
    init: function() 
        this._super();
        this.pushObject(
        App.CommunityModel.create(
            displayName: 'Twitter',
            linkUrl: 'https://twitter.com/#!/emberjs',
            imageUrl: 'http://icons.iconarchive.com/icons/iconshots/social-media-network/32/twitter-icon.png'
        ));
        this.pushObject(
        App.CommunityModel.create(
            displayName: 'GitHub',
            linkUrl: 'https://github.com/emberjs/ember.js',
            imageUrl: 'http://www.workinprogress.ca/wp-content/uploads/github.png'
        ));
    
);

App.CommunityView = Em.View.extend(
    templateName: 'community',
    contentBinding: 'App.CommunityController.content'
);

App.Router = Em.Router.extend(
    enableLogging: true,
    location: 'hash',

    root: Em.Route.extend(
        // EVENTS
        gotoHome: Ember.Route.transitionTo('home'),
        gotoStarting: Ember.Route.transitionTo('starting.index'),
        gotoCommunity: Ember.Route.transitionTo('community.index'),

        // STATES
        home: Em.Route.extend(
            route: '/',
            connectOutlets: function(router, context) 
                router.get('applicationController').connectOutlet('home');
            
        ),
        starting: Em.Route.extend(
            // SETUP
            route: '/starting',
            connectOutlets: function(router, context) 
                router.get('applicationController').connectOutlet('starting');
            ,
            // EVENTS
            gotoMVC: Ember.Route.transitionTo('mvc'),
            gotoEmber: Ember.Route.transitionTo('ember'),
            gotoIndex: Ember.Route.transitionTo('index'),

            // STATES
            index: Em.Route.extend(
                route: '/',
                connectOutlets: function(router, context) 
                    router.get('applicationController').connectOutlet('starting');
                
            ),
            mvc: Em.Route.extend(
                route: '/mvc',
                connectOutlets: function(router, context) 
                    router.get('applicationController').connectOutlet('aboutMVC');
                
            ),
            ember: Em.Route.extend(
                route: '/ember',
                connectOutlets: function(router, context) 
                    router.get('applicationController').connectOutlet('aboutEmber');
                
            )
        ),
        community: Em.Route.extend(
            // SETUP
            route: '/community',
            connectOutlets: function(router, context) 
                router.get('applicationController').connectOutlet('community');
            ,
            // EVENTS
            // STATES
            index: Em.Route.extend(
                route: '/',
                connectOutlets: function(router, context) 
                    router.get('applicationController').connectOutlet('community');
                
            )
        )
    )
);
App.initialize();​

【讨论】:

太好了,比我快得多。恕我直言,此示例应该是 ember 站点示例示例的一部分。 我正在编写一个示例,所以我已经准备好了一些模板。稍后我可能会修改小提琴以解决 CSS 类部分 太好了,谢谢!我同意这应该在 Ember 网站上。我发现 Ember 文档实际上非常缺乏 - 将它们放在一起需要相当长的时间。网站上的文档给我留下了很多问题,主要是如何将所有这些放在一起以形成一个实际的应用程序,而不仅仅是一个视图。而我在 1.0 天时学到的 Rails,截屏视频是一个很好的起点。我希望 Ember 有这样的东西。 一个小项目已添加到GitHub。这是我自己的学习过程,可能会随着我的进步帮助其他人理解它。欢迎贡献者。目标是在使用 Ember 开发应用程序时创建具有常见做法的示例。我很快就会添加它的 Rails 版本。当前使用 .NET Web API 如果我每个破 Ember 小提琴都有一美元……我绝对可以买午餐【参考方案2】:

我不喜欢 MilkyWayJoe 的回答,因为如果您迟早要更改状态的命名或您必须通过代码和视图进行的任何操作,那么还为每条路线添加一个函数似乎是不可取的. 我的方法更加程序化和模块化:

# Parent View-Tamplate, holding the navbar DOM elements
App.NavView = Ember.View.extend( 
  controller: App.NavArrayController
  templateName: "ember-nav"
)
# We push NavItems into this array
App.NavArrayController = Ember.ArrayController.create(
  content: Ember.A([])
)
# NavItem has two settable properties and 
# an programmatic active state depending on the router
App.NavItem = Ember.Object.extend(
  title: ''
  goto: null    # <=this is the name of the state we want to go to!
  active: (->
    if App.router.currentState.name == @.get "goto"
      true
    else
      false
  ).property('App.router.currentState.name').cacheable()
)
# the actual NavElement which gets the class="active" if the 
# property "active" is true, plus a on-click binding to
# make the Router transition to this state
App.NavItemView = Ember.View.extend(
 tagName: "li"
  classNameBindings: ["active"]
  click: ->
    App.router.transitionTo(@get('goto'))
    false
)

nav-view.hbs(用于 twitter-bootstrap 风格的导航)

<div class="nav-collapse collapse">
  <ul class="nav">
    #each App.NavArrayController
      #view App.NavItemView classBinding="active" gotoBinding="goto"
        <a href="#" bindAttr data-goto="goto"> title</a>
      /view
    /each
  </ul>
</div>

这样,我可以在路由器中创建和处理我的路由, 并排保持导航定义:

# put this somewhere close to the Router 
App.NavArrayController.pushObjects(
  [
    App.NavItem.create(
      title: 'Home'
      goto: 'home'
    ),
    App.NavItem.create(
      title: 'Chat'
      goto: 'chat'
    ),
    App.NavItem.create(
      title: 'Test'
      goto: 'test'
    )
  ]
)

【讨论】:

另外,这样做的好处是链接实际上是链接而不是操作 - 所以它们有一个 href 和浏览器操作,如“在新选项卡中打开”等,将起作用。 仅当您将a href="#" 设置为href="/#/unbound goto" 我同意你们的看法。我试图在代码的更新版本上解决这个问题,但并没有完全达到我想要的位置。现在新路由器已经启动,我将(在某个时候)更新它,以便您对这个实现的看法更加一致。我的借口是我在学习时写它,所以这是一次发现体验:P @Thomas:我已经提出了你的这个想法here。我已将代码翻译成 javascript(原来是 Ruby,对吗?),并更新了较新的 ember 版本(1.1.2)。

以上是关于使用 Ember 进行导航的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Ember CLI 正确生成资源和路由

在通过 NavigationControllerDelegate 进行交互式转换期间隐藏/取消隐藏导航栏的正确方法是啥?

如何在 ember.js 中处理表单提交?

toastr 和 ember.js

从 Promise 处理程序调用 Ember _super 方法

修复导航的正确方法是啥?