Ember.js възстановява превъртане на историята, нулиране на превъртане на връзката

Daniel F Pupius описа проблема като:

Много сайтове грешат това и е наистина досадно. Когато потребителят навигира с помощта на бутона за напред или назад на браузъра, позицията на превъртане трябва да бъде същата като последната, когато е бил на страницата. Това понякога работи правилно във Facebook, но понякога не. Изглежда, че Google+ винаги губи позицията ви при превъртане.

Така че вече има много въпроси относно нулирането на превъртането до горната част на страницата, когато разглеждате нова страница. Готварската книга на Ember.js също показва как да се свържете с Route.activate:

export default Ember.Mixin.create({
  activate: function() {
    this._super();
    window.scrollTo(0,0);
  }
});

Това обаче решава само половината от проблема. Когато потребителят използва бутоните назад/напред, позицията на превъртане няма да бъде възстановена, а просто нулирана.

Има доста опити за решаване на това, много чрез просто съхраняване на позицията на превъртане в екземпляра Ember.Controller, например в този статия. Това обаче е само частично решение. Ако контролерът се използва многократно, ще се запази само едно състояние на превъртане.

Как може да се запази прилагането на браузъра по подразбиране за възстановяване на старото състояние на превъртане? Следователно, не правете нищо, ако Route.activate е задействано от промяна на състоянието на историята на html5?


person Bouke    schedule 06.05.2015    source източник


Отговори (3)


Току-що реших този проблем в собственото си приложение.

Ако искате да го използвате само на места, които имат нужда от него, просто използвайте миксин:

ember g mixin remember-scroll

След това в mixins/remember-scroll.js заменете с:

import Ember from 'ember';

export default Ember.Mixin.create({

  scrollSelector: window,

  activate: function() {
    this._super.apply(this, arguments);
    var self = this;
    if( this.get('lastScroll') ){

      Ember.run.next(function(){
        Ember.$(self.scrollSelector).scrollTop(self.get('lastScroll'));
      });

    } else {
      Ember.$(this.scrollSelector).scrollTop(0);
    }
  },

  deactivate: function() {
    this._super.apply(this, arguments);
    this.set('lastScroll',Ember.$(this.scrollSelector).scrollTop());
  },

});

Ако искате автоматично да се смесва във всички маршрути, направете следното.

В Ember CLI създайте нов инициал.

ember g initializer remember-scroll

След това в initializers/remember-scroll.js заменете кода с това:

import Ember from "ember";

var rememberScroll = Ember.Mixin.create({

  scrollSelector: window,

  activate: function() {
    this._super.apply(this, arguments);
    var self = this;
    if( this.get('lastScroll') ){

      Ember.run.next(function(){
          Ember.$(self.scrollSelector).scrollTop(self.get('lastScroll'));
      });

    } else {
      Ember.$(this.scrollSelector).scrollTop(0);
    }
  },

  deactivate: function() {
    this._super.apply(this, arguments);
    this.set('lastScroll',Ember.$(this.scrollSelector).scrollTop());
  },

});

export function initialize(/* container, application */) {
  Ember.Route.reopen(rememberScroll);
}

export default {
  name: 'remember-scroll',
  initialize: initialize
};

Можете да премахнете първия миксин по-горе, ако използвате версията на инициализатора.

Това трябва да накара всичките ви маршрути да запомнят последната позиция на превъртане (ако сте били там преди) и да я приложат, когато се върнете там.

Въпреки че бих препоръчал да не го поставяте във всички маршрути, тъй като потребителите може да не очакват да бъдат върнати към предишна позиция на превъртане, ако е минало значително време от последното им посещение.

person JeremyTM    schedule 15.08.2015
comment
Мисля, че това няма да запомни две различни позиции на превъртане, ако контролерът е посетен два пъти? - person Bouke; 20.08.2015
comment
Този mixin се отнася за маршрута, а не за контролера. Той запомня позицията на превъртане, когато напускате маршрута (вижте раздела deactivate), след което я възстановява, когато се върнете. - person JeremyTM; 21.08.2015

Намерих решението от JeremyTM тук като цяло ефективно. Според моя опит обаче използването на метода deactivate води до несъответствия в стойността, зададена на lastScroll при преход, докато използването на метода за действие willTransition на маршрута води до последователно поведение на набора.

Ето модификацията на неговия миксин, която работи по-добре за мен:

import Ember from 'ember';

export default Ember.Mixin.create({
  activate: function() {
    this._super.apply(this, arguments);
    var self = this;

    if(this.get('lastScroll')){
      Ember.run.next(function(){
        Ember.$(window).scrollTop(self.get('lastScroll'));
      });
    } else {
      Ember.$(window).scrollTop(0);
    }
  },

  actions: {
    willTransition: function() {
      this._super.apply(this, arguments);
      this.set('lastScroll', Ember.$(window).scrollTop());
    }
  }
});

Имайте предвид също, че това все още ми се струва частично решение на проблема, тъй като не нулира превъртането при всички щраквания върху връзки (за разлика от навигациите на браузъра / промените в историята). Това се прави при първото щракване върху връзката, което зарежда маршрут, но всички последващи щраквания върху връзка към този маршрут също ще заредят предишната позиция на превъртане, като по този начин не успяват да разпознаят предвиденото от потребителя действие за зареждане на маршрута без позоваване на предишното му поведение на изглед ( още известен още като с позиция за превъртане за нулиране).

person Mark Hendrickson    schedule 29.06.2016

Инсталирайте тази добавка за ember ember-router-scroll, за да нулирате превъртането с възможности за възстановяване на историята на превъртане. Той използва HistoryLocation API на браузърите, така че работи веднага.

person Musaffa    schedule 23.08.2016