jQuery based revealer ad is laggy on mobile - javascript

Heyo,
I hope you guys can help me out. I tried to build a box that holds an advertisement. The revealer-box (lets call it that) sits in between the content and the ad has a fixed position and sits behind the content (it can't be seen, hidden through z-index and display: none). If the revealer-box is visible on the screen the ad gets a display: block. But the only place where it is visible is at the revealer-box, because all other elements have a higher z-index. Thus the revealer-box works similar to a window where you look through. This was all done and not an issue. The only problem is that it is kinda laggy on mobile (Galaxy S4, Androdid 5.0.1, Chrome). It seems like it has something to do with my jQuery. Let me post it here:
if($(window).width() < 601) {
showElem(".revealer-box");
} else {
hideElem(".revealer-box");
hideElem(".revealer-ad");
}
$(window).resize(function() {
if($(window).width() < 601) {
showElem(".revealer-box");
} else {
hideElem(".revealer-box");
hideElem(".revealer-ad");
}
});
$(window).scroll(function() {
if( isOnScreen(".revealer-box") && $(".revealer-box").hasClass("is-active") ) {
showElem(".revealer-ad");
if(flgCallGA) {
callGA.call($(".revealer-ad"));
flgCallGA = false;
}
} else {
hideElem(".revealer-ad");
}
});
function isOnScreen(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
var elemHeight = $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
function showElem(elem) {
if( !$(elem).hasClass("is-active") ) {
$(elem).addClass("is-active");
}
}
function hideElem(elem) {
if( $(elem).hasClass("is-active") ) {
$(elem).removeClass("is-active");
}
}
As you can see it is only displayed for mobile. And the is-active-class only gives a display: none. nothing more. i hope you can help me.
sincerely,
nunu

As Stan already pointed out, the "scroll" event is fired a few hundred times on a simple scroll. Remove the event listener on scroll and add it again after a short time.
function addListener(){
window.addEventListener("scroll", scrolling);
}
function scrolling(){
//remove the event listener
window.removeEventListener("scroll",scrolling);
window.setTimeout(addListener,500);
}
addListener();

Related

If Statements not Targeting Intended Screen Widths

I have some javascript being fired when the screen reaches certain widths... I am trying to make it mobile responsive and need it to fire at different points on different devices...
var screenWidth = window.innerWidth;
if (screenWidth <= 812 && screenWidth > 414) {
$(window).scroll(function() {
var fromTopPxFirstBgChange = 2300;
var scrolledFromtop = $(window).scrollTop();
if (scrolledFromtop > fromTopPxFirstBgChange) {
$('body').addClass('secondBg');
}
else {
$('body').removeClass('secondBg');
}
});
}
if (screenWidth <= 414 && screenWidth > 375) {
$(window).scroll(function() {
var changeBg = 2190;
var scrolledFromtop = $(window).scrollTop();
if (scrolledFromtop > changeBg) {
$('body').addClass('secondBg');
}
else {
$('body').removeClass('secondBg');
}
});
}
if (screenWidth <= 375 && screenWidth > 320) {
$(window).scroll(function() {
var changeBgImage = 2380;
var scrolledFromtop = $(window).scrollTop();
if (scrolledFromtop > changeBgImage) {
$('body').addClass('secondBg');
}
else {
$('body').removeClass('secondBg');
}
});
}
So for the first one for example, I would like the screen to apply those changes at 414-812px.
Basically the background image is supposed to change when I am scrolled to the position on the page that I specified in each if statement (the class "secondBg" is a class I specified in the CSS with the new background image... I don't know if this is a JS error or a problem with other code. It seems to work uniform when I just have one if statement but when I add the three they sort of work and overwrite one another. I think the if statements are pretty clear and cannot see the problem.
You shouldn't be binding your listeners inside the if statements. You should instead have 1 listener and do checks inside like so:
$(window).scroll(function() {
if($(window).scrollTop() < 500) {
// Your code here
}
// add more checks here
});
Also, I'd throttle that as it's a really heavy operation. Take a look at this.

jQuery: clone div multiple times on scroll

I'm trying to figure out how to repeatedly clone the contents of a div on scroll, thus giving the impression that the page goes on forever and ever. My markup thus far is as follows and a fiddle here too https://jsfiddle.net/guht49La/:
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800 && inserated == false) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
inserated = true;
} else {
}
});
Although this only inserts it once, as I want to keep inserting it every 800px (for example) thus giving the impression that the page goes on forever and ever. Any suggestions on this would be greatly appreciated!
This will work
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
inserated = true;
} else {
}
});
This is a complete guess, but perhaps give this a go:
var nextInsert = 800;
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nextInsert) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
nextInsert += 800;
} else {
}
});
It is working, but it clones the div just once because you changed the inserated variable to true after inserting the first clone. It will work indefinitely if you delete it:
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800 && inserated == false) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
// inserated = true;
} else {
}
});
Notice that inserated = true; is commented out.
That code, however, can (and almost certainly) creates a huge amount of clones, so I'd suggest controlling the scrolling insertion point using something along the lines of Nat Karmios answer
My suggestion is similar to jbmartinez answer, except I would drop the inserated variable altogether and use classes to determine elements to be cloned:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800) {
var $button = $('.hd').not(".cloned").clone();
$button.addClass("cloned");
($button).insertBefore('.ap');
} else {
}
});
Would still need to adjust the scrolling mark as noted above tho.

Automatically loading more posts (checking if element is visible on screen)

This function detects whether or not an element is visible on the screen. When a user scrolls to a "load" element I want to automatically request more posts to be displayed (AJAX). However, at the moment I have the following code:
function isScrolledIntoView(elem)
{
var $elem = $(elem);
var $window = $(window);
var docViewTop = $window.scrollTop();
var docViewBottom = docViewTop + $window.height();
var elemTop = $elem.offset().top;
var elemBottom = elemTop + $elem.height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
var scrolledCounter = 0;
setInterval(function(){
var scroll = isScrolledIntoView(".button.load-more");
if(scroll==true){
scrolledCounter++;
loadMorePosts(scrolledCounter);
}
},500);
It works fine, but if the element is constantly in view (as it would be for slower-ish connections loading the information), it then loads more every 500ms. I'm wondering what method would be better than setInterval (?) to accomplish what I want to do.
i.e.
If the user scrolls to the load element, function loadMorePosts is called just once, then if it's not visible anymore, re-allow the function to be called again, such that if it's visible again the function is called once more again.
You can use $(window).scroll() method. It will occur every time users scrolls the page.
I have added an isScrolling variable to prevent firing loadMorePosts more than once in a period.
var isScrolling = false;
$(window).scroll(function(){
var scroll = isScrolledIntoView(".button.load-more");
if (scroll==true && !isScrolling)
{
isScrolling = true; // Block this function
scrolledCounter++;
loadMorePosts(scrolledCounter);
setTimeout(function() { isScrolling = false; }, 500); // Unblock the function after 0.5s
}
});
JSFiddle DEMO (without isScrolling): http://jsfiddle.net/0wbf9dn2/

Detecting when div is scrolled to does not work

I'm having trouble detecting when a certain section of the page is scrolled down to. Once I get down to a certain ID or Class, I'd like to run a couple of functions.
I found this solution here, and tried this below, but the code does not activate:
// Once you scroll into that div ID, this still does not get hit:
$( "#slice_video" ).scroll(function() {
console.log('in scroll...');
});
// In the comments I also saw this solution, tried it but still nothing working:
function isScrolledIntoView(elem) {
// alert("method invoked");
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom) && (elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
if (isScrolledIntoView($('.eco_jumbotron'))){
// initialize modals:
modals.wireModals($());
// Animate in Tiles
animateTiles();
}
JsFiddle for first solution:
http://jsfiddle.net/leongaban/6n4bczmu/
JsFiddle for 2nd solution
http://jsfiddle.net/leongaban/yxkqafwn/
so your issue is you are trying to scroll on the wrong div firstly.. then you are checking the height of the entire window to that div.. so if you changed it to .container scroll event it would alert every time you scroll. what you want to do is check the scroll relative to the div you are scrolling. so something like this.
function isScrolledIntoView( elem, container )
{
var contTop = $(container).offset().top;
var contBottom = contTop + $(container).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= contBottom) && (elemTop >= contTop));
}
$( '.container' ).scroll(function() {
if ( isScrolledIntoView( $( '.box4' ) , $( '.container' ) ) )
{
console.log('HERE!');
}
});
WORKING FIDDLE
You have to listen for the scroll event on the container that has the overflow to scroll or auto.
This code did work:
$('.container' ).scroll(function() {
if($(".box4").position().top < $(".container").position().top + $(".container").height()){
// code
}
});
DEMO
I guess you can do better but it's a start.
I hope it helps.
EDIT:
Don't forget to handle the fact that with this method the event will fire every time you scroll a tiny little bit and the div's position is less than the containers (bottom-edge) position

Check if div is viewable in window?

I have a one page site with fixed navigation and using a scroll script, very similar to this: http://www.ivanjevremovic.in.rs/live/temptation/single/orange/index-cycle-slider.html
What I'm looking for is a way to check what section is viewable in the window to set the active state on the nav when using the browsers scroll bar, any ideas?
Here are all the variables you'll need...
var $myElt = $('.myElement'); // whatever element you want to check
var $window = $(window); // the window jQuery element
var myTop = $myElt.offset().top; // the top (y) location of your element
var windowTop = $window.scrollTop(); // the top of the window
var windowBottom = windowTop + $window.height(); // the bottom of the window
Then to make sure your element is within the window's range...
if (myTop > windowTop && myTop < windowBottom) {
// element is in the window
} else {
// element is NOT in the window
// maybe use this to scroll...
// $('html, body').animate({scrollTop: myTop}, 300);
}
jQuery reference:
http://api.jquery.com/offset/
http://api.jquery.com/height/
http://api.jquery.com/scrollTop/
Use $('#element').offset().top; to detect element top side.
$(window).scrollTop(); to detect current scroll position.
And $(window).height(); to detect current window height.
And after that steps you actually need only something easy math calculations.
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}
source: Check if element is visible after scrolling
see the following lazyload plugin:
http://plugins.jquery.com/files/jquery.lazyload.js__6.txt
the section which starts with the comment "return the status of the item relative to the current view" checks to see if an element is visible in the viewport.
If you are using jQuery just try to check the document position
$('html').position().top;
for example:
$(document).bind("scroll", checkLink);
function checkLink(){
/* Position will checked out after 1 sec when user finish scrolling */
var s = setTimeout(function(){
var docHeight = $('html').position().top;
var allLinks = $('.navigation a');
if ( docHeight < 0 && docHeight <= -1000 ) {
allLinks.removeClass('active');
$('a.firstlink').addClass('active');
} else
if ( docHeight < -1000 && docHeight <= -2000 ) {
allLinks.removeClass('active');
$('a.secondlink').addClass('active');
} else { /* .... */ }
$(document).bind("scroll", checkLink);
}, 1000);
$(document).unbind('scroll');
}
but guys in your example haven't held on this for a long time :) they just toggle classes on click
$('#navigation').localScroll();
$('#navigation li a').click( function () {
$('#navigation li a').removeClass("active");
$(this).addClass("active");
});
2022 answer - you don't have to use jQuery anymore for this
Now it is possible to use plain javascript with IntersectionObserver.
The problem with the other answers are that they fire off too many times.
For example you could to this:
var observer = new IntersectionObserver(function(entries) {
if(entries[0].isIntersecting === true) {
console.log('Element is in the window');
} else {
console.log("Element is not in the window");
}
});
observer.observe(document.querySelector(".myObject"));

Categories

Resources