2014-11-06 65 views
1

我正在尝试创建一个Ember应用程序,其中路径之间的滚动位置被保留,为用户提供浏览时更愉快的体验。在Ember中保留滚动位置

预期结果

如果我滚动500像素下来/网页B,点击一个链接到/网页A,点击浏览器的后退按钮,我应该回到了500px的滚动顶部。

实际结果

当点击浏览器的后退按钮,滚动顶部等于/网页A的高度。

如何重现

git clone https://github.com/eTilbudsavis/ember-scroll-demo 
cd ember-scroll-demo 
npm install 
ember serve 
open http://localhost:4200/pageb 

然后你一路滚动到底部,点击网页A链接,然后点击浏览器的后退按钮,你应该看到这个问题。

最后说明

我认为这种现象的原因是,当我点击浏览器的后退按钮,浏览器试图回到它离开这条道路之前所具有的位置滚动。由于Ember尚未呈现该视图,因此浏览器无法前往此处。它只能滚动到/ pagea的高度。

现在更棘手的是,如果我在浏览器的控制台上点击后手动设置滚动条顶部,也没有任何反应。看起来浏览器认为它是在正确的滚动顶部,即使它不是。如果我用鼠标单个滚动,浏览器会一直跳到它应该在的位置。

我希望我已经尽可能简洁地解释了这一点。否则,请随时询问更多细节。

谢谢!

+0

我我的答案更新,它现在应该在这两个Firefox和Chrome浏览器。 – 2014-11-07 12:07:03

+0

另一个答案,与mixin:http://reefpoints.dockyard.com/2014/05/05/preserve-scroll-position-in-ember-apps.html – givanse 2014-11-11 21:59:51

+0

我试过那个,但它并不真的特别是在Chrome中正常工作。 – user3365242 2014-11-14 11:49:57

回答

0

如果有人想使用它,我已经解决了问题,自己与这条路线的mixin:

`import Ember from 'ember'` 

Ember.$(window).on 'unload', -> 
    $(@).scrollTop 0 

    return 

PreserveScrollMixin = Ember.Mixin.create 
    # @property [Integer] the time to wait before running the scroll callback 
    # 
    scrollingTimeout: 100 

    # As soon as the route initializes, set the min height on the body and the scroll top on the window and listen to 
    # future scroll events. 
    # 
    beforeModel: -> 
     height = @getWithDefault 'controller.height', 0 
     scrollTop = @getWithDefault 'controller.scrollTop', 0 
     onScroll = => 
      Ember.run.debounce @, @runScrolled, @scrollingTimeout 

      return 

     Ember.$('body').css 'min-height', height 
     Ember.$(window).on 'scroll.scrollable', onScroll 
     Ember.$(window).scrollTop scrollTop 

     return 

    # When the route's model is ready, set the scroll top again to be sure. 
    # 
    afterModel: -> 
     scrollTop = @getWithDefault 'controller.scrollTop', 0 

     Ember.run.next @, -> 
      Ember.$(window).scrollTop scrollTop 

      return 

     return 

    # Sets the scroll top for the window. 
    # 
    runScrolled: -> 
     @set 'controller.scrollTop', Ember.$(window).scrollTop() 

     return 

    actions: 
     # When the route appears, allow the body to flow naturally. 
     # 
     didTransition: -> 
      Ember.$('body').css 'min-height', '100%' 

      return 

     # When the route is about to leave, stop listening to scroll events and set the current body height. 
     # 
     willTransition: -> 
      Ember.$(window).off 'scroll.scrollable' 
      @set 'controller.height', Ember.$('body').height() 

      return 

`export default PreserveScrollMixin` 
+0

现在你在控制器内存储滚动状态。如果控制器在整个应用程序中使用很多次,那么只会有一个滚动状态,对吧? – bouke 2015-05-06 15:27:56

+0

我已经改变了一点,所以滚动状态不在控制器内。相反,它位于名为'scrollTops'的全局(模块)对象中,我坚持像这样进行更改:scrollTops [@routeName] = Ember。$(window).scrollTop()。 – user3365242 2015-05-21 07:36:21

+0

同样的问题仍然存在,因为您现在可以为每个路线存储一个滚动状态,而不是每个历史项目的单个滚动状态。 – bouke 2015-05-27 18:03:19

0

你似乎试图依赖浏览器的滚动状态,但你没有指定你使用的浏览器。

我试过创建长页面并转到外部链接,当前Chrome返回后保存了滚动状态,但Firefox没有。

因此,不依靠浏览器,'状态保存'问题的一般答案是使用queryParams

我创建了滚动状态样本保存到queryParams。请注意,我使用replaceState来阻止浏览器为每个滚动条创建新的历史记录条目。

App = Ember.Application.create({}); 

App.ApplicationRoute = Ember.Route.extend({ 
    queryParams: { 
    scrollTop: { 
     replace: true 
    } 
    }, 
    setupController: function(controller) { 
    $(window).on('load', function() { 
     $(document).scrollTop(controller.get('scrollTop')); 
    }); 
    } 
}); 

App.ApplicationController = Ember.Controller.extend({ 
    queryParams: ["scrollTop"], 
    scrollTop: 0, 
    handleScroll: function() { 
    this.set('scrollTop', $(document).scrollTop()); 
    }, 
    bindScrollEvent: function() { 
    $(window).on('scroll', Ember.run.bind(this, this.handleScroll)); 
    }.on('init') 
}); 

JSBin是here

更新:我用固定版本替换了代码示例,该版本实际适用于Firefox和Chrome。

+0

谢谢你的回答。我很感激!不过,我有点担心在URL中保存滚动状态。我想不出有这样的网站吗?让IMO在每次滚动时更新URL都有点令人困惑。自从问我的问题以来,我一直在研究一个潜在的解决方案:https://gist.github.com/anonymous/b51b25ec8d1a36cba752。它在CoffeeScript中 - 我希望你不介意。它似乎适用于所有浏览器。你怎么看? – user3365242 2014-11-08 00:35:27

+0

它看起来不错,但是,我还没有理解从要点,滚动状态被保存(会话,localStorage)? 如果您想将存储滚动状态的URL传递给其他人,那么在URL中存储可能很有用。我还没有看到任何实际上这样做的网站。你可能是第一个:) 其实,没有Ember就很难做到。 – 2014-11-08 19:20:59

+0

我实际上不希望在访问外部资源后返回网站时保存滚动状态。我想要确保网站体验记住每个前进和后退路线的滚动位置。 – user3365242 2014-11-14 11:49:16