2014-11-06 113 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