Ember.js锚链接

时间:2013-08-26 13:43:58

标签: javascript ember.js

我在主页上有一个我需要链接的登录框。登录框在html中有id="login“,我有一个链接就像这个<li><a href="#login">Login</a></li>所以点击它会带我到登录div但是当我点击刷新或直接转到锚点的链接我得到Uncaught Error: No route matched the URL 'login'

任何人都有任何想法如何在Ember完成这个简单的任务?感谢。

更新

以下是我的代码的样子:

导航

 <ul class="nav navbar-nav pull-right">
  <li><a href="#login">Signup</a></li> 
  <li>{{#linkTo 'about'}}About{{/linkTo}}</li>
 </ul>

以及我在页面下方的某处

<section id="login">
 -- some content
</section>

7 个答案:

答案 0 :(得分:15)

查询参数

基于查询参数方法更新的答案(截至2013年12月21日的当前特色标志)

基于alexspellers原始JSFiddle,可以在此处找到完整的演示:http://jsfiddle.net/E3xPh/

Router中,添加对查询参数的支持

App.Router.map ->
  @resource 'index', path: '/', queryParams: ['anchor']

使用您选择的Route,在anchor方法中为setupController查询参数设置属性。

App.IndexRoute = Em.Route.extend
  setupController: (controller, context, queryParams) ->
    controller.set 'anchorLocation', queryParams.anchor

最后在您的Controller中为anchorLocation财产制作观察员。

App.IndexController = Em.ArrayController.extend
  showAnchor: (->
    $elem = $(@anchorLocation)
    $scrollTo = $('body').scrollTop($elem.offset().top)
  ).observes 'anchorLocation'

现在,您可以在模板中使用以下代码滚动到某个锚点,或将浏览器指向/#/?anchor=#login

{{#linkTo anchor='#login'}}Show login{{/linkTo}}

简单行动方法

根据您在第一个答案的评论中所写的内容,可能的答案。在这里把简单的东西搞得一团糟。

http://jsbin.com/osEfokE/11

单击“索引”链接将转到IndexRoute并将您滚动到登录框,但URL未反映此更改,并且键入#login也不起作用。

App.ApplicationRoute = Ember.Route.extend({
    events: {
        goToLink: function(item, anchor) {
            var $elem = $(anchor);
            var $scrollTo = $('body').scrollTop($elem.offset().top);

            this.transitionToRoute(item.route).then($scrollTo);  //.transitionTo is depricated
        }
    }
});

当您想要滚动到锚点时,您将在模板中使用goToLink,而不是使用linkTo。

<ul>
  <li><a href="#/" {{action goToLink "index" "#login"}}>Index</a></li>
  <li>{{#linkTo about}}About{{/linkTo}}</li>
  <li>{{#linkTo contact}}Contact{{/linkTo}}</li>
</ul>

答案 1 :(得分:8)

问题在于Ember使用URL中的哈希部分来存储应用程序的当前状态。我自发地看到了两种可能的解决方案。

1 - * 不要让Ember使用您网址的哈希部分。 *因此请使用Ember的 HTML5历史记录位置实施。这将导致yourdomain.com/users/1/之类的网址没有#

App.Router.reopen({
  location: 'history'
});

2 - 不要使用这种技术。而是使用jQuery 来滚动到相关部分。这看起来像这样:

<ul class="nav navbar-nav pull-right">
  <li><a {{action jumpToLogin}}>Signup</a></li> 
  <li>{{#linkTo 'about'}}About{{/linkTo}}</li>
</ul>

并在相应的视图中:

App.YourView = Ember.View.extend({
  jumpToLogin : function(){
    $('html, body').animate({
        scrollTop: $("#login").offset().top
    }, 2000);
  }
});

对于这个小功能,这似乎有很多代码,但我想这是一个更好的用户体验吧? 实际上,您可以通过将此逻辑提取到mixin 来改进此方法,因此您不必一遍又一遍地重复它:

App.ScrollToMixin = Ember.Mixin.create({
  scrollDuration : 2000, //default
  scrollTo : function(selector){
    $('html, body').animate({
        scrollTop: $(selector).offset().top
    }, this.get("scrollDuration");
  )
});
// mix it into your View
App.YourView = Ember.View.extend(App.ScrollToMixin, {});

并在模板中使用它:

<ul class="nav navbar-nav pull-right">
  <li><a {{action scrollTo "login"}}>Signup</a></li> 
  <li>{{#linkTo 'about'}}About{{/linkTo}}</li>
</ul>

PS:我没有使用mixin测试代码。我并不完全确定String“login”会像那样传递给动作处理程序。所以你必须测试: - )

答案 2 :(得分:5)

我使用了一个组件,它也可以通过动作扩展为支持查询参数。

var ScrollToComponent = Ember.Component.extend({
  tagName: 'a',
  anchor: '',

  scrollTo: function () {
    var anchor = this.get('anchor'),
      $el = Ember.$(anchor);

    if ($el) {
      Ember.$('body').scrollTop($el.offset().top);
    }
  }.on('click')
});

这就是你如何使用它:

{{#scroll-to anchor=anchor}}Jump To Anchor{{/scroll-to}}

anchor#my-id

修改

这是一个执行此https://www.npmjs.com/package/ember-scroll-to

的ember-cli插件

答案 3 :(得分:1)

我使用kroovy的答案中的简单行动方法在Ember工作。

由于Ember改变了它的API,我不得不稍微改变kroovys的方法。

有两件事发生了变化:

  1. 不推荐使用Ember.Route中的事件,并将其替换为Ember.Controller中的操作
  2. 而不是transitionTo你必须使用transitionToRoute
  3. 以下是我在Ember版本1.7.0中使用它的方法

    Ember Handlebars-Template new.hbs

    {{!-- Navigation --}}
    <ul>
     <li {{action 'goToLink' "new" "#part1"}}>Part 1</li>
     <li {{action 'goToLink' "new" "#part2"}}>Part 2</li>
    </ul>
    
    {{!-- content --}}
    <div id="part1" class="row">...</div>
    <div id="part2" class="row">...</div>
    

    Ember App.Controller NewController.js

    App.NewController = Ember.ArrayController.extend({
    
     actions: {
    
        goToLink: function(item, anchor) {
            console.log('NewController > goToLink');
            var $elem = $(anchor);
            var $scrollTo = $('body').scrollTop($elem.offset().top);
    
            this.transitionToRoute(item.route).then( $scrollTo);
        }
    }
    });
    

答案 4 :(得分:1)

以前大多数答案的问题是,如果在点击其中带有“href hash / fragment / id”的“链接”时路由没有改变,那么ember路由器将不会触发执行所需的钩子大多数以前的解决方案。

这在具有多个“标题”的页面中很明显,您希望允许用户从“导航/索引或链接列表”跳转到页面的相关部分(例如服务条款或页面) 。

在这些情况下,ember要求你“选择进入完全转换”,这样路由器就会触发它的挂钩,即使路由没有改变但查询参数有。有关详细信息,请参阅"opting into a full transition"

注意:使用此“opt in”时将触发的唯一记录的挂钩是模型挂钩。

我认为这种“完全转换”选择仅用于在查询参数上刷新模型时使用,例如排序或过滤。

不可否认,这看起来有点像黑客,但上面的“选择加入”可用于滚动到我们的div / anchor标签。在将来,选择加入也可以解雇其他更合适的钩子(setupController特别适合)。

此外,如果有人在谷歌上搜索。我也尝试在路线上使用“willTransition”和“didTransition”动作。虽然他们在从其他路线转换时确实被解雇了,但是当他们从同一条路线转换到自身时,它们也无法触发。

最后,对某些人来说应该是显而易见的(但最初并不适合我),为了让浏览器滚动到有问题的ID,需要完全加载dom。所以我们必须在Ember.run.schedule('afterRender',回调中执行滚动。

仅供参考我现在正在使用最新的ember-cli,ember.js和ember-data:

  • ember-cli:1.13.7
  • ember:1.13.6
  • ember-data:1.13.7

应用程序/ router.js

  this.route('about', {
    queryParams: ['anchor']
  });

路由/ about.js

import Ember from 'ember';

export default Ember.Route.extend({
  queryParams: {
    anchor: {
      refreshModel: true
    }
  },
  model: function(params) {
    var aboutController = this.controllerFor('about');
    aboutController.set('anchorLocation', params.anchor);
  }
});

应用程序/控制器/ about.js

import Ember from "ember";
export default Ember.Controller.extend({
  queryParams: ['anchor'],
  anchor: '',
  showAnchor: function() {
    var _this = this;
    Ember.run.schedule('afterRender', function scrollToAnchor(){
      var elem = Ember.$(_this.anchorLocation);
      elem.get(0).scrollIntoView(true);
    });
  }.observes('anchorLocation'),
});

应用程序/模板/ footer.js

          <ul>
            <li>
              {{#link-to "about" (query-params anchor='#contact')}}Contact{{/link-to}}
            </li>
            <li>
              {{#link-to "about" (query-params anchor='#support')}}Support{{/link-to}}
            </li>
            <li>
              {{#link-to "about" (query-params anchor='#team')}}Team{{/link-to}}
            </li>
          </ul>

答案 5 :(得分:0)

我的问题是,如果我从另一个页面点击目标链接,它将转到目标但不向下滚动到页面的正确部分。几个小时后,这是我的修复:

注意:我正在使用ember-cliemblemember 1.8

我的navigation barapplication.emblem

中的

链接

li 
 a#concept-link click=jumpToConcept
  | Le Concept 

然后,如果我已经在页面上,我只需向上滚动。如果我还没有在页面上,那么我将使用查询参数concept=true

转到该页面 action

中的

application controller

scrollToConcept: function() {
  Ember.$(document).ready(
    Ember.$('html, body').animate({
        scrollTop: Ember.$("#concept").offset().top
    }, 750)
  )
},

 //allow clicking of link with specific id to go to that part of page
jumpToConcept : function(){
  if (this.get('currentPath') === 'index') {
    this.send('scrollToConcept');
  } else {
    this.transitionToRoute('index', { queryParams: {concept: true}});
  }
}
index controller

然后添加concept query params

export default Ember.Controller.extend(

  queryParams: ['concept'],
  concept: null
}

然后我在scrollToConcept(我刚去过的页面)中添加了index view事件,该事件侦听页面加载并检查concept queryParam。如果concept=true我滚动到页面的概念部分。

index view

scrollToConcept: function() {
    if (this.controller.get('concept') === 'true') {
        Ember.$('html, body').animate({
        scrollTop: Ember.$("#concept").offset().top
    }, 750);
    }
}.on('didInsertElement')

然后对于普通index links,我添加了一个设置concept=null的操作,以便concept query param不会显示在网址中。

<{1}}

中的

链接

nav bar

然后在a click=goToIndex h3 id={logoClass} Happy Dining 我转到application controller,将index route设置为null(因此它不会显示在网址中)并滚动到顶部(只是加入它)在页面上较低)

concept query param

希望将来帮助人们!!!

答案 6 :(得分:0)

如果有人正在尝试使用Ember 3解决此问题,那么我有解决方案。它使用了与其他人提到的相同的queryParams方法,但是我无法在控制器上进行任何操作。我发现可行的唯一方法是使用route + jQuery.ready函数。

// route/application.js
import Route from '@ember/routing/route';
import $ from 'jquery';

export default Route.extend({
  queryParams: {
    anchor: null
  },

  setupController: function(controller, context, params) {
    let anchor = params.queryParams.anchor;

    // On ready, find the anchor offset and go there
    $().ready(function() {
      let anchorOffset = $("#" + anchor).offset().top
      window.scrollTo(0, anchorOffset);
    });
  }
});

然后在模板中,照常使用您的queryParams:

{{#link-to "path.to.page" (query-params anchor="my-anchor")}}My Link{{/link-to}}

这里唯一的问题是它每次都会重新加载页面,但除此之外似乎还行得通-希望它能对某人有所帮助。