我试图创建一个Ember应用程序,保留路线之间的滚动位置,为用户提供更愉快的浏览体验。
预期结果
如果我在/ pageb上向下滚动500px,请单击指向/ pagea的链接,单击浏览器后退按钮我应该回到500px滚动顶部。
实际结果
单击浏览器后退按钮时,滚动顶部等于/ pagea的高度。
如何重现
git clone https://github.com/eTilbudsavis/ember-scroll-demo
cd ember-scroll-demo
npm install
ember serve
open http://localhost:4200/pageb
然后您一直滚动到底部,单击pagea链接,然后单击浏览器后退按钮,您应该会看到问题。
最后的笔记
我认为这种行为的原因是当我点击浏览器后退按钮时,浏览器会尝试滚动回到离开该路线之前的位置。因为Ember尚未呈现该视图,所以浏览器无法访问。它只能滚动到/ pagea的高度。
现在,更棘手的是,如果我进入浏览器的控制台并在点击后手动设置滚动顶部,也没有任何反应。似乎浏览器认为它在右侧滚动顶部,即使它不是。如果我用鼠标进行单个滚动,浏览器会一直跳到它原本应该到达的位置。
我希望我已尽可能简洁地解释这一点。否则,请随时询问更多详细信息。
谢谢!
答案 0 :(得分: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中使用。
答案 1 :(得分: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`