Scrollbar in ReactJS - javascript

I want page to scroll up gently when modal opens opens. But it is not working as expected. Instead, the scrollbar is moving abruptly upward. Am I doing anything wrong here ?
ScrollingSteps() {
console.log(window.pageYOffset);/* This is giving me 0, even when scroll
bar is not on the top. Why is it showing this strange behavior ? */
if (window.pageYOffset === 0) {
clearInterval(this.state.intervalId);
}
window.scroll(0, window.pageYOffset - 5);// It is showing abrupt change
console.log(document.body.scrollTop,document.body.style.top)/*Even these 2 are 0 here. Don't understand why!*/
}
ScrollingToTop() {
let myID = setInterval(this.ScrollingSteps.bind(this), 5);
}

with window.scrollTo you can make use of behavior prop adn provide value smooth
window.scrollTo({
top: 0,
left: window.pageYOffset - 5,
behavior: 'smooth',
})
see here for details:
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo

Related

Is it possible to control the scrolling speed in js?

I added an eventlistener on scroll. Is it possible to control the speed of page scrolling with js (I can't use jquery because the site was built on elementor).
Window.scrollTo() has only two parameters behavior = smooth | auto.
Below is a sample code.
document.addEventListener("scroll", (event) => {
const axisY = window.scrollY;
if (axisY > 0 && axisY < 10800) {
window.scrollTo({
top: 10800,
left: 0,
behavior: 'smooth'
});
}
});
Is there a speed-controlled analog to Window.scrollTo()?

How to give ease animation when adding scrolleft?

I'm building a horizontal scrolling div, something like a slider.
Something like this
The thing is, this thing is between other contents, so I had to use a custom javascript code that I found online to make this horizontal sliding div act like a vertical div.
`
(function () {
init();
var g_containerInViewport;
function init() {
setStickyContainersSize();
bindEvents();
}
function bindEvents() {
window.addEventListener("wheel", wheelHandler);
}
function setStickyContainersSize() {
document
.querySelectorAll(".sticky-container")
.forEach(function (container) {
const stikyContainerHeight =
container.querySelector(".container").scrollWidth;
container.setAttribute(
"style",
"height: " + stikyContainerHeight + "px"
);
});
}
function isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top <= 0 && rect.bottom > document.documentElement.clientHeight
);
}
function wheelHandler(evt) {
const containerInViewPort = Array.from(
document.querySelectorAll(".sticky-container")
).filter(function (container) {
return isElementInViewport(container);
})[0];
if (!containerInViewPort) {
return;
}
var isPlaceHolderBelowTop =
containerInViewPort.offsetTop < document.documentElement.scrollTop;
var isPlaceHolderBelowBottom =
containerInViewPort.offsetTop + containerInViewPort.offsetHeight >
document.documentElement.scrollTop;
let g_canScrollHorizontally =
isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if (g_canScrollHorizontally) {
containerInViewPort.querySelector(
".projAnimContainer"
).scrollLeft += evt.deltaY;
}
}
})();
This code works.
It does stick the div when user comes to that div, and its not letting the user go down till he finishes scrolling that horizontal div.
So user scrolls down, comes to the slider div, slides(scrolls down) but it doesn't scroll down but scrolls to right. And after user finishes scrolling in that div and div ends, it leaves the user and user can continue the rest of the website as normal.
It works as I said but the problem is I dont want it to scroll ugly.
I want it to scroll smooth.
containerInViewPort.querySelector(
".container"
).scrollLeft += evt.deltaY;
This is the action that adds the scrolling horizontally to my div.
I've tried changing it with this
document.querySelector(".container").scrollBy({
top: 0,
left: +evt.deltaY,
behavior: "smooth",
});
and
$(".container").animate(
{ scrollLeft: "+=" + evt.deltaY + "" },
1000,
"easeOutSine"
);
this..
Both didn't work.
They try to work but they can't, I mean for example if I change the code with the jquery one (easeoutsine one), it scrolls 1 time with ease thats good but then jumps to the end of the div and scrolling more up or down doesn't work. it stuck.
And if I use the other document.query... one it tries to scroll with ease but the scrolling to right effect ends and it goes to the next content after this slider without finishing the slider completely. I think when I add ease, it adds more px than it should and It finishes the slider before it should.
I hope I managed to describe my question.
Thanks all.
I've tried jquery and normal ease animations.

OnScroll Fold the View - React Native

I'm really bad at math, I am trying to calculate the top section of the scrollView as I want it to come on top of the top View to make more place for the scrollView.
I know that I could use Animate.View to accomplish this, But due to a component(RecyclerListView) Im unable to do that. So my Idee is while I scroll Down I move the component ItemList up until is at -150 and when I scroll up, I will move until the value scrollY hit 0.
There is already a post here on Stack(here) That displays what I want.
Here is my code.
<View> this is the View i want to cover/fold <View>
<ItemList style={{top:scrollY}}
onScroll={(nativeEvent, offsetX, offsetY)=>{
// when scroll down, scrollY should not exeede 0
// when i scroll up, scrollY should not be more -150
var maxScroll = 0;
var minScroll = -150;
// How should i calculate and set setScrollY()
}}
columnPerRaw={columnPerRar}
itemHeight={150}
onIni={(s: any) => {
setScroll(s);
}}
onItemPress={(item, index) => itemClick(item as item)}
items={data ?? []}
renderItem={renderItem}
onEndReached={() => {
if (globalContext.value.panination && !isLoading)
setEffectTrigger(Math.random());
}}
keyName="name"
/>
Update
I have done like #Nnay said but its not to smoth
var maxScroll = 0; // when i scroll up, scrollY should not be more then 0
var minScroll = -150; // when scroll down, scrollY should not exeede -150
var top = lastPos - offsetY;
if (top >minScroll && top <=maxScroll)
setScrollY(top);
lastPos = offsetY;
I have done it like
no matter how you choose to trigger this behaviour (be it scroll position or scroll direction), you should probably use conditional classes.
to get the scroll direction, you will need to store the previous scroll position.
if oldPosition - newPosition < 0 you have scrolled down, else you have scrolled up.
if you want the position of the element to trigger it, you should opt for setting a boolean to true or false which triggers the class. something like:
<View class={{this.show ? 'show' : ''}}>
where show is a boolean local to your component.
your show class can then handle the height of the element which will automatically push the following content down (provided it isn't positioned absolute) and you can smoothen this by using transition: .25s in css. otherwise it will jump
your scroll handler could then set the boolean depending on the scroll direction with something like:
this.show = oldPos - newPos > 0;
which will return true if the user has scrolled up which seems to be the behaviour you referenced in the link
let me know if this satisfies your question so I can edit and adapt the answer accordingly
ps: if you just set the top of your element while it has a static position, it won't work. also it will just jump to that position since you're not smoothing anything
EDIT: if CSS animations and transitions don't work and you cannot use react-native's Animate.View, the only option that doesn't require external packages is to set an interval animation if react-native doesn't support the AnimationsAPI
I haven't tried using the AnimationsAPI in react-native yet so I would advise to test that first since it's much more performant.
if you want to use the interval animation, I would still recommend sticking to the boolean solution above, but removing the class and adding a height variable in the style attribute of the <View>
make sure to store your interval in a variable so you can clear it.
if (this.height < 150 /* no idea what height you need, play around */ && show && !this.interval){
this.interval = setInterval(() => {
this.height += 1;
}, 10)
} else if (this.height > 0 && !show && !this.interval) {
this.interval = setInterval(() => {
this.height -= 1;
}, 10)
} else {
clearInterval(this.interval)
}
something like this should work. keep in mind that I haven't used interval animations in years so you might need to play around with some values

give an offset with scrollIntoView

I am using scrollIntoView() to go to a selected input. But I set it to top, so I would like to give with an offset to that method.
But this seems not to work I also checked the scrollTo method and did that like this:
this.keyboard.onKeyboardShow().subscribe(() => {
console.log('document.activeElement!!!!', document.activeElement)
// document.activeElement.scrollIntoView(true);
const top = document.activeElement.getBoundingClientRect().top + window.scrollY;
console.log(top);
window.scroll(0, top)
window.scrollTo({
top: top,
behavior: 'smooth'
});
// document.activeElement.scrollTo(0, 10);
window.scrollBy(-100, 0);
});
But this will not scroll to that element anymore. Could somebody help me out setting an offset to scrollIntoView()

How to get and set the current web page scroll position?

How can I get and set the current web page scroll position?
I have a long form which needs to be refreshed based on user actions/input. When this happens, the page resets to the very top, which is annoying to the users, because they have to scroll back down to the point they were at.
If I could capture the current scroll position (in a hidden input) before the page reloads, I could then set it back after it reloads.
The currently accepted answer is incorrect - document.documentElement.scrollTop always returns 0 on Chrome. This is because WebKit uses body for keeping track of scrolling, whereas Firefox and IE use html.
To get the current position, you want:
document.documentElement.scrollTop || document.body.scrollTop
You can set the current position to 1000px down the page like so:
document.documentElement.scrollTop = document.body.scrollTop = 1000;
Or, using jQuery (animate it while you're at it!):
$("html, body").animate({ scrollTop: "1000px" });
You're looking for the document.documentElement.scrollTop property.
Update 2021: browsers inconsistencies with scrollTop seem to have disappeared.
There are some inconsistencies in how browsers expose the current window scrolling coordinates. Google Chrome on Mac and iOS seems to always return 0 when using document.documentElement.scrollTop or jQuery's $(window).scrollTop().
However, it works consistently with:
// horizontal scrolling amount
window.pageXOffset
// vertical scrolling amount
window.pageYOffset
I went with the HTML5 local storage solution... All my links call a function which sets this before changing window.location:
localStorage.topper = document.body.scrollTop;
and each page has this in the body's onLoad:
if(localStorage.topper > 0){
window.scrollTo(0,localStorage.topper);
}
this will give you the px value of scroll from top
document.documentElement.scrollTop
Nowadays it seems like the get is working with: window.scrollX and window.scrollY. This could be an alternative way to solve it.
var stop = true;
addEventListener('drag', (event) => {
if (event.clientY < 150) {
stop = false;
scroll(-1)
}
if (event.clientY > ($(window).height() - 150)) {
stop = false;
scroll(1)
}
if (document.body.getBoundingClientRect().y === 0){
stop = true;
}
if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
stop = true;
}
});
addEventListener('dragend', (event) => {
stop = true;
});
var scroll = function (step) {
var scrollY = $(window).scrollTop();
$(window).scrollTop(scrollY + step);
if (!stop) {
setTimeout(function () { scroll(step) }, 20);
}
}
Now you can also use window.scrollTo({ top: 0, behavior: 'smooth' }); instead of using that jQuery solution above for the animation. Here is the documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo

Categories

Resources