Pull-to-refresh in (mobilen!) Webseiten nachzubauen, ist jetzt keine Raketenwissenschaft, aber doch so viel Aufwand, dass sich ggf. eine Library lohnt. Viele (? einige? apeatling, ember-gestures, …) bauen aber auf hammer auf, und das hat einen Bug (Beispiel, es gibt weitere Tickets) im Zusammenspiel von Panning (also dem “Pull” in “Pull-to-refresh”) und Scrolling. Zusammengefasst: Es geht nur eines von beiden. Mit ein wenig Drumherumgehacke bekommt man das etwas näher zusammengeführt, aber entweder kommt PanEnd dann gar nicht (was das “refresh” schwierig macht), oder bspw. die PanMove-Events kommen nicht zuverlässig (wodurch man den “pull” nicht 1:1 an den Finger des Nutzers hängen kann).
Ein npm-Modul, das nicht auf hammer aufbaut, wäre pulltorefreshjs (getestet mit 0.1.11 und 0.1.13):
1 2 3 4 5 6 |
PullToRefresh.init({ mainElement: '.myCssSelector', onRefresh: () => { console.log('hello moto') }, }); |
In Ember sieht das als Komponente so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import Component from '@ember/component'; import PullToRefresh from 'npm:pulltorefreshjs'; import {get, set} from '@ember/object'; import {getOwner} from '@ember/application'; import {inject as service} from '@ember/service'; export default Component.extend({ classNames: ['pull-to-refresh'], router: service(), currentRouteInstance: undefined, didInsertElement() { this._super(...arguments); const owner = getOwner(this); const currentPath = owner.lookup('controller:application').currentPath; set(this, 'currentRouteInstance', owner.lookup(`route:${currentPath}`)); // TODO use unique identifier for mainElement, store result of init() PullToRefresh.init({ mainElement: '.pull-to-refresh', onRefresh: () => { get(this, 'currentRouteInstance').refresh(); }, }); }, willDestroyElement() { this._super(...arguments); // TODO destroy current ptr only; id is returned by init() PullToRefresh.destroyAll(); }, }); |
Auf dem Handy sollte das so schon funktionieren. Auf dem Desktop hatte ich das Phänomen, dass Hochcrollen immer erst beim zweiten mal funktioniert hat (und auch dann nur, wenn zwischen Versuch 1 und 2 nicht zu viel Zeit lag). Weil: Die Lib immer beim Hochscrollen den Loader anzeigt, wenn man die Funktion shouldPullToRefresh
nicht vom default !window.scrollY
ummapt, bspw. auf
1 2 3 4 |
shouldPullToRefresh: () => { let scrollTop = this.$().parent()[0].scrollTop; return scrollTop === 0; }, |
Hochscrollen geht sonst nur, so lange der Loader angezeigt wird 🙃