Is there anyway to call a method on vue after the viewer scrolled certain amount of page percentage?
For example, i would like to run a method to display an offer after the viewer has scrolled 80% of the page from top to bottom.
<script>
export default {
mounted() {
window.addEventListener("scroll", this.handleScroll);
},
destroyed() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
handleScroll(event) {
// Any code to be executed when the window is scrolled
const offsetTop = window.scrollY || 0;
const percentage = (offsetTop * 100) / document.body.scrollHeight;
// Do something with the percentage
},
},
};
</script>
Note If you want to do something ( for example task() ) with a condition that the percentage is equal or greater than some value you must considering a data variable container that how many times that condition is true and do the operation just one time after that.
<script>
export default {
data() {
return {
reached: false, // checker container
};
},
methods: {
task() {
console.log("Triggered just one time >= 80");
},
handleScroll(event) {
// ... After calculating the percentage ...
if (percentage >= 80) {
if (!this.reached) {
this.task();
this.reached = true;
}
} else this.reached = false;
},
},
};
</script>
Live Demo
Related
I am changing the background-color of my navbar on scroll event, it works, but the problem is that the function changeNavBar is triggered on every scroll movement. I'd like to know how can I make it be triggered only at a certain point of the screen.
For instance, let's say the function should be called only when the YPosition is bigger than 50, once it is called it wouldn't be called again, unless the screen is scrolled up and the navbar reaches a point smaller than 50. In other words, we start at 0, it reaches 50 it is called, but it isn't called if the screen keeps being scrolled down, it won't be called it YPosition is 100, 200, 1000, doesn't matter. But if the page is scrolled up and reaches 50'inch it will be called.
This is my code:
const Navigation = props => {
let [navBg, setNavBg] = React.useState('transparent')
let navbarStyle = {
backgroundColor: navBg
}
const changeNavBar = () => {
if (window.scrollY > 50) {
setNavBg('blue')
} else {
setNavBg('transparent')
}
console.log('test')
}
React.useEffect(() => {
window.addEventListener('scroll', changeNavBar);
return () =>
window.removeEventListener('scroll', changeNavBar);
}, []);
return (
<div style={navbarStyle}>
<Logo />
<MenuNavigation />
</div>
)
}
The issue is not what happens within the function changeNavBar. What I want is to prevent the function to be called when it is not necessary.
Instead of performing state updates every time, check if it needs to be changed first.
const changeNavBar = () => {
if (window.scrollY > 50) {
if(navBg !== 'blue') setNavBg('blue')
} else {
if(navBg !== 'transparent') setNavBg('transparent')
}
}
I'm making a progress bar, which should receive progress status from method submitAction, in which value for progress bar constantly updating. Here my code:
1.Parent component
<template>
<div>
<progressbar-component :value="progressState"></progressbar-component>
</div>
</template>
<script>
import ProgressBar from './Progress.vue'
export default {
components: {
'progressbar-component': ProgressBar
},
data () {
return {
...
progress: 0
...
}
},
computed: {
...
progressState () {
return this.progress
}
...
},
methods: {
...
submitAction: function (event) {
...
let percent = 0
setInterval(function () {
if(someState > 0) {
this.progress = percent % 100
percent += 10
}
}, 200)
...
}
}
}
</script>
2. Child (progress bar) component
<template>
<div class="progress">
{{ value }}
</div>
</template>
<script>
export default {
name: 'progressbar-component',
props: {
value: {
type: Number,
default: 0
}
}
}
</script>
Aim:
Updating value in Progress Bar's component, while setInterval is running.
Problem:
value doesn't update in child component.
P.S.
Some parts of initial code are just left out to simplify problem representation:
this.progress value changes correctly in parent, and I can track it
through debugger progress bar component also works correctly and
initial value of progress (i.e. 0) passed fine.
Well, this took me some time. Classic mistake. The problem is you don't really change components' progress ever:
submitAction: function (event) {
let percent = 0
setInterval(function () {
if(someState > 0) {
this.progress = percent % 100 // <---- `this` here doesn't refer to the component
percent += 10
}
}, 200)
}
to make it work do:
submitAction: function (event) {
let percent = 0
setInterval(() => { // <---- arrow function doesn't have their own `this`, so `this.progress` will refer to the components' value
if(someState > 0) {
this.progress = percent % 100
percent += 10
}
}, 200)
}
Here is what I have now it will work but if window width is under 1024 it will still trigger even though it is only set to trigger if over 1024
$(function () {
$('#hamburger').click(function () {
$('div.burger_nav').slideToggle();
});
$(window).resize(function () {
if ($(window).width() < 1024) {
$('.nav_shown').hide();
$('div.footerdiv_2').hide();
$('div.hidden_nav').hide();
$('div.burger_btn').show();
$('#ft').removeClass('footerdiv_3').addClass('footer_img_clear');
} //end of if
else {
$(".nav_shown").show();
$('.footerdiv_2').show();
$('div.burger_btn').hide();
$('#ft').removeClass('footer_img_clear').addClass('footerdiv_3');
$(document).scroll(function () {
var headerShow = $(this).scrollTop();
if (headerShow > 200) {
$('div.hidden_nav').fadeIn();
$(".nav_shown").hide();
} else {
$('div.hidden_nav').fadeOut();
$(".nav_shown").show();
}
});
} //end of else
});
});
It looks like you want to modify the document when the window reaches a certain breakpoint, in this case 1024 pixels. This is known as responsive web design.
Instead of updating the screen every time on resize, it's useful to set a flag for triggering a breakpoint.
$(function() {
$('#hamburger').click(function(){
$('div.burger_nav').slideToggle();
});
var currentlySmall = false;
function update() {
if ($(window).width() < 1024 && !currentlySmall) {
currentlySmall = true;
console.log('Less than 1024');
$('.nav_shown').hide();
$('div.footerdiv_2').hide();
$('div.hidden_nav').hide();
$('div.burger_btn').show();
$('#ft').removeClass('footerdiv_3').addClass('footer_img_clear');
}
else if ($(window).width() >= 1024 && currentlySmall) {
currentlySmall = false;
console.log('More than 1024');
$(".nav_shown").show();
$('.footerdiv_2').show();
$('div.burger_btn').hide();
$('#ft').removeClass('footer_img_clear').addClass('footerdiv_3');
}
}
//Calling this in the else part above will bind a new scroll event each time
//Instead, if this should only happen when the screen is large, use the
//flag you created
$(document).scroll(function () {
if (!currentlySmall) {
var headerShow = $(this).scrollTop();
if (headerShow > 200) {
$('div.hidden_nav').fadeIn();
$(".nav_shown").hide();
} else {
$('div.hidden_nav').fadeOut();
$(".nav_shown").show();
}
}
});
$(window).resize(update);
update(); //Force initial calculation since resize won't be called when page loads
});
Now the changes you make in the above update() function will only occur when the screen sizes changes past that 1024 breakpoint instead of every time the screen is resized.
Fiddle: http://jsfiddle.net/25nfqxzk/1/
Edit
Expanding off blgt's comment, I don't believe you need to bind the scroll event in the if-else. It can be assigned outside and also use the same trigger flags.
The following script successfully adds or removes a "fix" class to an element (#sideBarWrapper) in desktop browsers, depending on the distance a user has scrolled.
(function (exocet, $, undefined) {
// Distance of sidebar from document top
function sideBarTop () {
return $eventSideBar.offset().top;
}
// Distance user has scrolled
function scrollDist () {
return $(window).scrollTop();
}
// Toggle sidebar class
function sideBarStick(sbt) {
if (sbt-30 < scrollDist()) {
$sideBarWrapper.addClass('fix');
} else{
$sideBarWrapper.removeClass('fix');
}
}
// Scroll events
function scroll() {
$eventSideBar = $('#eventSideBar');
$sideBarWrapper = $('#sideBarWrapper');
var sbt = sideBarTop();
return $(window).scroll(function () {
sideBarStick(sbt);
});
}
exocet.init = function () {
scroll();
};
}(window.exocet = window.exocet || {}, jQuery));
Invoked like so:
$(function() {
exocet.init();
});
The problem is, in Safari for iPad, the class doesn't seem to get added until the document has come to a halt, often long after the sidebar has scrolled out of view. How can I compensate for this?
How can i get the current scrolling position of my browser?, i want to fire events base on page position.This is what I tried:
var scroll_position=document.viewport.getScrollOffsets();
window.onscroll = function (event) {
if(scroll_position>1000)
{
alert('xxxxxxxxxxx');
}
Assuming that you're always going to be testing with window, you can use window.scrollY:
window.onscroll = function (event)
{
if(this.scrollY > 1000)
{
alert('xxxxxxxxxxx');
}
}
jsFiddle Demo
Try with:
window.onscroll = function (event) {
if (window.scrollY > 1000) {
alert('xxxxxxxxxxx');
}
}
As hsz said, do
window.onscroll = function (event) {
var scroll_position = document.viewport.getScrollOffsets();
if (scroll_position > 1000)
{
alert('xxxxxxxxxxx');
}
}
The problem with your code:
var scroll_position=document.viewport.getScrollOffsets();
scroll_position is only set once, when the page loads - therefore it stays the same (probably 0) and the alert never comes up because scroll_position is less than 1000.
hsz put the statement that sets scroll_position into the window.onscroll function, so it is updated every time the page scrolls.