如何使用新的Ember路由器绑定到链接的活动类?

时间:2013-01-14 22:54:06

标签: ember.js

我在我的Ember.js应用中使用Twitter Bootstrap进行导航。 Bootstrap在包含导航链接的active标记上使用li类,而不是在链接本身上设置active类。

Ember.js的新linkTo助手会在链接上设置一个active类,但是(据我所知)并没有提供任何可以挂钩的属性。

现在,我正在使用这种丑陋的方法:

{{#linkTo "inbox" tagName="li"}}
  <a {{bindAttr href="view.href"}}>Inbox</a>
{{/linkTo}}

这将输出:

<li class="active" href="/inbox"><a href="/inbox">Inbox</a></li>

这就是我想要的,但不是有效的HTML。

我还尝试从父视图绑定到生成的LinkView的active属性,但如果这样做,父视图将在插入之前呈现两次,从而触发错误。

除了手动重新创建linkTo帮助器内部使用的逻辑以将active类分配给链接之外,还有更好的方法来实现这种效果吗?

9 个答案:

答案 0 :(得分:27)

我们肯定需要一个更公开,永久的解决方案,但这样的事情现在应该有效。

模板:

<ul>
{{#view App.NavView}}
  {{#linkTo "about"}}About{{/linkTo}}
{{/view}}

{{#view App.NavView}}
  {{#linkTo "contacts"}}Contacts{{/linkTo}}
{{/view}}
</ul>

视图定义:

App.NavView = Ember.View.extend({
  tagName: 'li',
  classNameBindings: ['active'],

  active: function() {
    return this.get('childViews.firstObject.active');
  }.property()
});

这取决于几个限制因素:

  • 导航视图包含单个静态子视图
  • 您可以使用<li>的视图。有关如何从JavaScript定义或Handlebars自定义视图元素的详细信息in the docs

我提供了a live JSBin这项工作。

答案 1 :(得分:9)

我接受了@alexspeller的好主意并将其转换为ember-cli:

应用/组件/链路li.js

export default Em.Component.extend({
    tagName: 'li',
    classNameBindings: ['active'],
    active: function() {
        return this.get('childViews').anyBy('active');
    }.property('childViews.@each.active')
});

在我的导航栏中,我有:

{{#link-li}}
    {{#link-to "squares.index"}}Squares{{/link-to}}
{{/link-li}}
{{#link-li}}
    {{#link-to "games.index"}}Games{{/link-to}}
{{/link-li}}
{{#link-li}}
    {{#link-to "about"}}About{{/link-to}}
{{/link-li}}

答案 2 :(得分:8)

您还可以使用嵌套链接:

{{#link-to "ccprPracticeSession.info" controller.controllers.ccprPatient.content content tagName='li' href=false eventName='dummy'}}
  {{#link-to "ccprPracticeSession.info" controller.controllers.ccprPatient.content content}}Info{{/link-to}}
{{/link-to}}

答案 3 :(得分:6)

以katz的答案为基础,您可以在点击导航元素的active时重新计算parentView属性。

App.NavView = Em.View.extend({

    tagName: 'li',
    classNameBindings: 'active'.w(),

    didInsertElement: function () {
        this._super();
        var _this = this;
        this.get('parentView').on('click', function () {
            _this.notifyPropertyChange('active');
        });
    },

    active: function () {
        return this.get('childViews.firstObject.active');
    }.property()
});

答案 4 :(得分:5)

我刚刚编写了一个组件,以使其更好一些:

App.LinkLiComponent = Em.Component.extend({
  tagName: 'li',
  classNameBindings: ['active'],
  active: function() {
    return this.get('childViews').anyBy('active');
  }.property('childViews.@each.active')
});

Em.Handlebars.helper('link-li', App.LinkLiComponent);

用法:

{{#link-li}}
  {{#link-to "someRoute"}}Click Me{{/link-to}}
{{/link-li}}

答案 5 :(得分:2)

我重新创建了内部使用的逻辑。其他方法似乎更加骇人。这也可以更容易地重用我可能不需要路由的其他地方的逻辑。

像这样使用。

{{#view App.LinkView route="app.route" content="item"}}{{item.name}}{{/view}}

App.LinkView = Ember.View.extend({
    tagName: 'li',
    classNameBindings: ['active'],
    active: Ember.computed(function() {
      var router = this.get('router'),
      route = this.get('route'),
      model = this.get('content');
      params = [route];

      if(model){
        params.push(model);
      }

      return router.isActive.apply(router, params);
    }).property('router.url'),
    router: Ember.computed(function() {
      return this.get('controller').container.lookup('router:main');
    }),
    click: function(){
        var router = this.get('router'),
        route = this.get('route'),
        model = this.get('content');
        params = [route];

        if(model){
            params.push(model);
        }

        router.transitionTo.apply(router,params);
    }
});

答案 6 :(得分:1)

您可以跳过扩展视图并使用以下内容。

{{#linkTo "index" tagName="li"}}<a>Homes</a>{{/linkTo}}

即使没有href,Ember.JS仍然会知道如何挂钩LI元素。

答案 7 :(得分:0)

对于同样的问题,我来自基于jQuery的解决方案,不确定性能损失,但它开箱即用。我重新打开Ember.LinkView并扩展它。

Ember.LinkView.reopen({
    didInsertElement: function(){
        var el = this.$();

        if(el.hasClass('active')){
            el.parent().addClass('active');
        }

        el.click(function(e){
            el.parent().addClass('active').siblings().removeClass('active');
        });
    }
});

答案 8 :(得分:0)

撰写本文时的答案已过时。在Ember的更高版本中,如果您使用{{link-to}},当当前路由与目标链接匹配时,它会在'active'元素上自动设置<a>类。

因此,只需编写您的css,期望<a>active,并且它应该开箱即用。

幸运的是,该功能已添加。这里所有的东西都需要解决这个问题&#34;问题&#34;先前非常荒谬。