I am confused as to why this is not working, please could someone point me in the right direction? I have wrote some JQuery to slide down a submenu. However when moving the mouse around the menu it will fire thousands of events I am trying to have it wait for a hide to finish before doing another slidedown. However this does not seem to work:
$("li.title").children('ul').hide();
var hidden = true;
$("li.title").hover(
function() {
if (hidden == true){
var height = $(this).children('ul').height() + $(this).height();
$(this).height(height);
$(this).children('ul').slideDown();
var hidden = false;
}
},
function() {
$(this).height(25);
$(this).children('ul').hide(function() {
var hidden = true;
});
}
);
Remove var from your hidden variable within the callback functions in hover. You're reassigning those variables locally, so its not listening to the global hidden variable.
Change this:
var hidden = false;
to this:
hidden = false;
You need to remove var. The problem is you are creating a new instance of hidden scoped to your callback functions and not seeing the global hidden.
$("li.title").children('ul').hide();
var hidden = true,
myTimeout;
$("li.title").hover(
function() {
clearTimeout(myTimeout);
myTimeout = setTimeout(function(){
if (hidden == true){
var height = $(this).children('ul').height() + $(this).height();
$(this).height(height);
$(this).children('ul').slideDown();
hidden = false; //Removed var here
}
},100);
},
function() {
clearTimeout(myTimeout);
myTimeout = setTimeout(function(){
$(this).height(25);
$(this).children('ul').hide(function() {
hidden = true; //and here
});
},100);
}
);
Related
I just want to make an exit animation but I've got problems with the text inside the box which I want to hide.
$(".dropdown").click(function () {
var dropdownC = $(this).find(".dropdownc");
var dropdownUl = $(this).find("ul");
if (dropdownC.css("visibility") == "visible") {
dropdownC.removeClass("comein").addClass("comeout");
var hide = function () {
dropdownC.addClass("hide");
};
setTimeout(hide, 300);
} else {
dropdownC.removeClass("hide").removeClass("comeout").addClass("comein");
}
});
Here's the jsfiddle. Thank you for any help.
I would use display: block / none instead of visiblilty: visible / hidden
https://jsfiddle.net/dabvkmrL/1/
I have a custom function that I want to make dynamic as much as possible because, as you can see right now, whenever it gets to the trigger point, the two lines of text both come in at same time.
I want the second line of text to wait a bit (maybe halfway through the first line of text's animation) before it starts firing up the function.
My solution is to set parameters when creating the function to pass in different values for each new instance of the function and probably put a delay or queue between them to stop them from executing at the same time.
i.e. $(document).scroll(revealTextOnScroll(paragraph1, overlay1);
$(document).delay(2000).scroll(revealTextOnScroll(paragraph2, overlay2);
Is this possible?
https://codepen.io/alexyap/pen/jmQqvQ?editors=0010
$(document).ready(function(){
var text = $("p");
var overlay = $(".someYellowOverlay");
var flag = false;
$(document).scroll(revealTextOnScroll);
function revealTextOnScroll() {
var scrollPos = $(document).scrollTop();
if (scrollPos >= 250 && flag === false) {
flag = true;
revealText();
} else if (scrollPos < 250) {
flag = false;
$(text).css("display", "none");
$(overlay).css("transform-origin", "left center");
}
function revealText() {
$(overlay).addClass("someAnimation").delay(250).queue(function(next){
$(this).css("transform-origin", "right center");
next();
}).delay(125).queue(function(next){
$(text).css("display", "block");
next();
}).delay(250).queue(function(next){
$(this).removeClass("someAnimation");
next();
})
}
}
})
When you define this:
var overlay = $(".someYellowOverlay");
overlay can hold a single element OR a collection (many elements).
By the way, you don't need to redo a lookup for element after.
$(overlay) is useless... You can use overlay directly.
Now have in mind that it may be a collection, so what you will do will apply on each of them.
That is why I took the parents instead.
I now can "cycle" through them to apply the delays I want to their children.
Here is the code, you can play with it in CodePen.
Feel free to ask if you have questions.
;)
$(document).ready(function(){
var text = $("p");
var overlay = $(".someYellowOverlay").parent();
var flag = false;
$(document).scroll(revealTextOnScroll);
function revealTextOnScroll() {
var scrollPos = $(document).scrollTop();
var targetPos = $("header").offset().top;
if (scrollPos >= 250 && flag === false) {
flag = true;
revealText();
} else if (scrollPos < 250) {
flag = false;
text.css("display", "none");
overlay.children().css("transform-origin", "left center");
}
function revealText() {
var delayBetweenLines = 2000/overlay.length;
for(i=0;i<overlay.length;i++){
overlay.eq(i).children().first().addClass("someAnimation")
.delay((i*delayBetweenLines)+250).queue(function(next){
$(this).css("transform-origin", "right center");
next();
})
.delay((i*delayBetweenLines)+125).queue(function(next){
$(this).next().css("display", "block");
next();
})
.delay((i*delayBetweenLines)+250).queue(function(next){
$(this).removeClass("someAnimation");
next();
})
}
}
}
});
I am trying to create a website that automatically scrolls to each section upon a single scroll action. This means that the code has to check if the page is scrolled up or scrolled down. I believe the code below solves my problem but the scroll action is fired more than once while the page is scrolling. You will see that the first alert in the if statement reaches 5 instead of the desired 1. Any help on the matter would be highly appreciated.
[Note] I am using the velocity.js library to scroll to each section within the container.
var page = $("#content-container");
var home = $("#home-layer-bottom");
var musicians = $("#musicians");
var athletes = $("#athletes");
var politics = $("#politics");
var bio = $("#politics");
var pages = [ home,musicians,athletes,politics,bio ];
var pageCur = 0;
var lastScrollTop = 0;
page.scroll(function(){
var st = $(this).scrollTop();
var pageNex = pageCur + 1;
if (st > lastScrollTop){
alert(pageNex);
pages[pageNex].velocity("scroll", { container: $("#content-container") });
} else {
alert(pageCur-1);
pages[pageCur-1].velocity("scroll", { container: $("#content-container") });
}
lastScrollTop = st;
pageCur = pageNex;
});
The scroll event (as well as the resize event) fire multiple times as a user does this. To help this, the best practice is to debounce. However, I've never gotten that to work. Instead, I use a global boolean to check if the function has fired.
var scrolled = false;
page.on('scroll', function(){
if(!scrolled){
scrolled = true;
//do stuff that should take a while...
scrolled = false;
};
});
This worked for me!
var ScrollDebounce = true;
$('.class').on('scroll',
function () {
if (ScrollDebounce) {
ScrollDebounce = false;
//do stuff
setTimeout(function () { ScrollDebounce = true; }, 500);
}
})
I want to put a little delay for onmouseout event for a group of sub items in a drop down menu. But I don't want to use css transitions.
I set it with .hover() and setTimeout method but I wanted to put it only for a specific elements in menu - in this case just for sub items so I used if else statement for them. I have no idea why this if else statement does't work.
Here is my javascript code:
var selectors =
{
element: '.main-menu li:has(ul)'
}
var opacityWorkaround = function ($element, value) {
$element.css('opacity', value);
};
var getAnimationValues = function (visible) {
var result = {
visibility: visible
};
result.opacity = visible === 'visible' ? 1 : 0;
};
var mouseActionHandler = function ($element, visible, opacityValue) {
$element
.stop()
.css("visibility", 'visible')
.animate(getAnimationValues(visible),
3000,
function () {
$(this).css("visibility", visible);
opacityWorkaround($(this), opacityValue);
});
};
var onMouseIn = function () {
var $submenu = $(this).children("ul:first");
if ($submenu) {
mouseActionHandler($submenu, 'visible', 1);
}
};
var onMouseOut = function () {
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($submenu) {
mouseActionHandler($submenu, 'hidden', 0);
} else if ($global) {
setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
};
$(selectors.element).hover(onMouseIn, onMouseOut);
I put 1500ms delay and the $global variable is referring to sub items in menu that I want to make disapear with that delay. I wanted to achieve this when user move mouse cursor out of 'some items >' tab.
Here is my fiddle example.
http://jsfiddle.net/PNz9F/1/
Thanks in advance for any help!
In the example you have in your question $submenu always has a value so the else if statement is never run. You can check for a class instead.
var timeout;
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($(this).hasClass('menu-item')) {
mouseActionHandler($submenu, 'hidden', 0);
mouseActionHandler($global, 'hidden', 0);
clearTimeout(timeout);
} else if ($(this).hasClass('global')) {
timeout = setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
you should be able to just use the :hover selector in your code to check whether the user is hovering over the element or not and run code accordingly
so im a little rusty with my JS, but here is my code...
basically i have an image, that on mouseover, it cycles through a hidden div full of other images... fading it out, replacing the src, and fading back in. it works great. but once it gets through all the images, i want it to start back over and keep looping through them until the mouseout event stops it.
i thought i could just call the function again from within the function cycle_images($(current_image));, but that leads to the browser freaking out, understandably. what is a good method to accomplish this?
$.fn.image_cycler = function(options){
// default configuration properties
var defaults = {
fade_delay: 150,
image_duration: 1500,
repeatCycle: true,
};
var options = $.extend(defaults, options);
this.each(function(){
var product = $(this);
var image = $('div.image>a.product_link>img', product);
var description = $('div.image>div.description', product);
var all_images = $('div.all_images', product);
var next_image = ($(all_images).find('img[src="' + $(image).attr('src') + '"]').next('img').attr('src')) ? $(all_images).find('img[src="' + $(image).attr('src') + '"]').next('img') : $(all_images).children('img').first();;
// mouseover
image.fadeOut(options.fade_delay, function(){
image.attr('src', next_image.attr('src'));
image.fadeIn(options.fade_delay);
});
if (options.repeatCycle){
var loop = function() {
product.image_cycler();
}
setTimeout(loop,options.image_duration);
}
});
};
$(document).ready(function() {
$('div.product').hover(function(){
$(this).image_cycler();
}, function(){
$(this).image_cycler({repeatCycle: false});
});
});
It sounds like you want it to re-cycle and stop on mouseout.
After you define the cycle_images() function, add a flag, repeatCycle
cycle_images.repeatCycle = true;
At the end of the cycle_images function, add a recursive call with a timeout
if (this.repeatCycle) {
var f = function() {
return cycle_images.apply(this, [$current_image]);
}
setTimeout(f,50);
}
Then in mouseout,
cycle_images.repeatCycle = false;