Open simonflick opened 3 years ago
Needed this feature so I built a custom component based on the existing uk-scroll. For anyone needing this, or as a reference to ship this in a future version. Had to modify utils/viewport:scrollIntoView, but as the new variable defaults to 1, there are no breaking changes.
Usage: uk-velocityscroll="offset:200; velocity:0.4"
-- will throttle the speed to 40%.
/*
UIkit 3 has no speed control for animated scroll ATM.
This is a custom implementation allowing to pass a velocity multiplier.
Code from util/viewport.js
added velocity variable, divide getDuration result by it
*/
function scrollIntoView(element, {offset: offsetBy = 0, velocity = 1} = {}) {
const parents = UIkit.util.scrollParents(element);
let diff = 0;
return parents.reduce((fn, scrollElement, i) => {
const {scrollTop, scrollHeight} = scrollElement;
const maxScroll = scrollHeight - UIkit.util.getViewportClientHeight(scrollElement);
let top = Math.ceil(
UIkit.util.offset(parents[i - 1] || element).top
- UIkit.util.offset(UIkit.util.getViewport(scrollElement)).top
- offsetBy
+ diff
+ scrollTop
);
if (top > maxScroll) {
diff = top - maxScroll;
top = maxScroll;
} else {
diff = 0;
}
return () => scrollTo(scrollElement, top - scrollTop).then(fn);
}, () => Promise.resolve())();
function scrollTo(element, top) {
return new Promise(resolve => {
const scroll = element.scrollTop;
const duration = getDuration(Math.abs(top)) / velocity;
const start = Date.now();
(function step() {
const percent = ease(UIkit.util.clamp((Date.now() - start) / duration));
UIkit.util.scrollTop(element, scroll + top * percent);
// scroll more if we have not reached our destination
if (percent !== 1) {
requestAnimationFrame(step);
} else {
resolve();
}
})();
});
}
function getDuration(dist) {
return 40 * Math.pow(dist, .375);
}
function ease(k) {
return 0.5 * (1 - Math.cos(Math.PI * k));
}
}
document.addEventListener('readystatechange',function(){
UIkit.component('velocityscroll', {
/*
Code from core/scroll.js
added velocity variable and pass it to scrollIntoView
*/
props: {
offset: Number,
velocity: Number
},
data: {
offset: 0,
velocity: 1,
},
methods: {
scrollTo(el) {
if (UIkit.util.trigger(this.$el, 'beforescroll', [this, el])) {
scrollIntoView(el, {offset: this.offset, velocity: this.velocity}).then(() =>
UIkit.util.trigger(this.$el, 'scrolled', [this, el])
);
}
}
},
events: {
click(e) {
if (e.defaultPrevented) return;
e.preventDefault();
const targetId = `${escape(decodeURIComponent((this.$el.hash || '').substr(1)))}`;
this.scrollTo(document.getElementById(targetId));
}
}
})
});
It's very strange that this feature was already available.
Yootheme referred here because I need the option to change the delay of the smooth scrolling.
https://yootheme.com/support/question/141440#answer-452580
The option of jbjhjm is unfortunately not an option, because Yootheme Pro does not support this and always sets uk-scroll as default.
But I also don't want to add a separate JavaScript to try to block the uk-scroll feature somehow, just because the developers of UIKit thought to remove the feature is a good idea and Yootheme Pro doesn't want to offer an option to simply disable uk-scroll completely. 🤦
In my case, I really need it, since it is hurting the usability.
@janschoenherr @saschadube
Summary
What feature are you requesting? What problem does it solve?
The timing function of uk-scroll is hard coded but some projects have tight requirements and need a different speed. This was already implemented in UIkit 2. It could be implemented by adding a parameter that defines a speed multiplier (default 1.0) or the total time the scroll takes in milliseconds:
uk-scroll="speed: 1.4"
oruk-scroll="duration: 750"
(analogous to UIkit 2)Priority
On a scale of 1-5, how important is this feature to you? Please explain.
The current speed doesn't hurt the usability so this change is only cosmetic -> 1