I created a menu that shows its sub-menu on hover using some CSS and jquery. Thing is, it acts a bit funny in case user hovers lots of times on the menu item. This is the URL: http://91.202.168.37/~ibi/, and this is the jquery code (inside document ready):
if ($(window).width()>991) //menu script desktop or laptop
{
$('#mob-main-menu > li.menu-item-has-children').hover(function(event){
event.preventDefault();
$(this).children('a').toggleClass('bold600');
$(this).children('a').siblings('.sub-menu').slideToggle();
});
}
else // menu script touch device
{
$('#mob-main-menu > li.menu-item-has-children').click(function(event){
if ($(this).children('a').siblings('.sub-menu').css('display') == 'none')
{
event.preventDefault();
console.log('hidden');
}
$(this).children('a').toggleClass('bold600');
$(this).children('a').siblings('.sub-menu').slideToggle();
});
}
I tried to use setTimeout() function but couldn't get it to work. can I limit the code to queue no more than 2 times, no matter how many hovers it counted? and than after x time to set it back to zero? any other idea to make it work better will be happily accepted.
try make animation with .stop() function it clears the animation queue so it should work correctly
$(this).children('a').siblings('.sub-menu').stop().slideToggle();
Related
I'm trying to create a generic function that can be placed just once in my site and work across multiple pages, nice and lightweight.
I want to be able to make certain divs on the site fade-in when you reach 10px above them on the scroll.
I want to do this by simply adding the following attributes to my divs:
.fade-in-block
#specific-block-name
The idea is that I could go through the site, add this class and an ID, and the animation would work.
I almost have it working except for one thing, the scroll listening constantly continues to console.log after the function has been called. I don't like this as it feels like it's going to be constantly trying to apply the animation, which won't really be seen from the front-end but I feel the constant maths behind the scenes could slow stuff down.
Here is my jQuery:
$('body .fade-in-block').each(function(){
var block = '#'+$(this).attr('id');
console.log('Block class is = '+block);
var offset = $(block).offset().top;
var $w = $(window).scroll(function () {
if ($w.scrollTop() > offset - 10) {
console.log('reached block turn-on point for '+block);
$(block).removeAttr('id'); // remove the ID from the element so the script doesn't continue to find the element
// fade and rise animation here
}
});
});
And here is a JSFiddle. It works just fine, but once you hit the block you'll see it logs constantly every pixel scrolled.
I tried to remedy this by removing the selecting id from the element once the event has occurred, but it continues to run.
Scroll and resize events both have this problem and the solution is said to be debouncing. However, I've never actually gotten debouncing to work properly. Instead I typically create a sort of switch that is turned off once the scroll condition has activated. In your case, since you have multiple elements, you would need to assign a switch to each element.
$(window).on('scroll', function(){
$('.fade-in-block').each(function(){
var appear = $(this).attr('data-appeared');
if(!appear){
$(this).attr('data-appeared', true);
//do something to $(this)
}
})
})
Here I'm adding a data attribute after it has appeared and checking for it again once it has.
I want to slideDown() a div when the appropriate radio is selected, and slideUp the active one.
However, as it is now, in some cases it's being pushed down, in other cases pushed up.
(Private -> Shop = Up, Shop -> Private = Down)
I want it to always be pushed down. What am I doing wrong?
Here's the current state on JSFiddle: http://jsfiddle.net/mfmU7/
And the raw Javascript code:
$(document).ready(function() {
$("#private").click(function() {
$('#registration-brand, #registration-shop').slideUp();
$('#registration-private').slideDown();
});
$("#shop").click(function() {
$('#registration-brand, #registration-private').slideUp();
$('#registration-shop').slideDown();
});
$("#brand").click(function() {
$('#registration-shop, #registration-private').slideUp();
$('#registration-brand').slideDown();
});
});
It's all about position in the DOM (or z-index):
$(document).ready(function() {
$('.btn').on('click', function() {
var that = $('#registration-'+this.id);
$('.registration-type:visible').not(that).slideUp().before(that.slideDown());
});
});
FIDDLE
I had same problem and I resolve it by adding:
position:absolute;
bottom:85%;
to CSS and it solves your isue here
but then u have to again place those divs
Here: http://jsfiddle.net/isair/mfmU7/4/
The problem (that some slide up visually and some slide down visually) is caused because, in your original code, all the animations are occurring at once and the divs are vertically placed one above the other. So the top one looks like it is sliding down but the other two, while sliding down, look like they are popping up from the bottom because of the one that is in the process of hiding.
I like doing it this way so one action doesn't start until the others are over:
$("#private").click(function() {
$('#registration-brand, #registration-shop').slideUp(function() {
$('#registration-private').slideDown();
});
});
FIDDLE HERE
The problem with doing that (like I usually do) is that the function gets called twice, once when the already hidden div finishes hiding, which is almost immediately, and once after the other div finishes hiding (4/10 sec later). The second one does nothing because the appearing div is already fully visible (or almost so).
So ... another solution is needed.
This one has a whole different look because it waits until both slide up actions are done (even though one div is already hidden) before starting the slide down. The 'promise()' creates something that will be finished when all the 'slideUp()' calls complete their animation and the 'always()' calls the function when that is done.
$("#private").click(function() {
$('#registration-brand, #registration-shop').slideUp().promise().always(function() {
$('#registration-private').slideDown();
});
});
ALTERNATE FIDDLE
I am currently making a website that includes a menu navigation almost identical to the one found at fotopunch.com only instead of pointing down it points up. Anyways, I wrote the code using jquery/javascript for the menu and it works but I am wondering if there is a way to make it so that the hover function doesn't take effect for a specified amount of time. That way when you hover quickly over an item it doesn't cause the page to load unnecessarily. If anyone has any suggestions I would greatly appreciate it.
Below is a copy of part of my code to create the menu navigation. Another issue I am having is if you hover over too many navigation items in a row the arrow lags behind. I am hoping that by creating a wait time before the hover function takes effect that it would mostly correct this issue.
$("div#menu .reps").hover(function() {
if(current_slide != "reps"){
$(".arrow").animate({"left":"135px"});//move the arrow
if(current_slide == "clients"){
$(".clients_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
else if(current_slide == "services"){
$(".services_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
else{
$(".training_display").stop(true, true).fadeOut().hide();
$(".reps_display").fadeIn().show();
current_slide = "reps";
}
}
});
I think that something that you can do, although there is probably a better way is:
declare a function where you place all the code with a condition:
function hoverFunc(option)
{
if($(option).is(':hover'))
{
all the code to show the menu
}
}
And on the over function you do:
$("div#menu .reps").hover(function() {
setTimeout("hoverFunc('"+getOptionName+"')",milliseconds);
});
The idea is: when over, set a timeout and when the timeout is reached, check if the mouse is over and then do whatever you want, the hardest point is to pass the reference to the function, but you can pass the name of the item just getting it from html or a rel attribute.
But if you dont need the reference it is really ease, just call the function and check the element.
There is another option that maybe is more interesting for you. You can add a delay to the all the effects and add a stop(true) before, this way, if the user change the tag fast, the events will be cancelled, but it will change if the user goes through an option fast and goes out of the menu.
You an use the delay on some of your calls such as:
$(".reps_display").delay(100).fadeIn().show();
Or you can make some of the show and hide have a longer duration: show(2000) for instance.
We're trying to make sure our JavaScript menu, which loads content, doesn't get overrun with commands before the content in question loads and is unfurled via .show('blind', 500), because then the animations run many times over, and it doesn't look so great. So I've got about six selectors that look like this:
("#center_content:not(:animated)")
And it doesn't seem to be having any effect. Trying only :animated has the expected effect (it never works, because it doesn't start animated), and trying :not(div) also has this effect (because #center_content is a div). For some reason, :not(:animated) seems not to be changing the results, because even when I trigger the selector while the div in question is visibly animated, the code runs. I know I've had success with this sort of thing before, but the difference here eludes me.
$("#center_content:not(:animated)").hide("blind", 500, function () {
var selector_str = 'button[value="' + url + '"]';
//alert(selector_str);
var button = $(selector_str);
//inspectProperties(button);
$("#center_content:not(:animated)").load(url, CenterContentCallback);
if (button) {
$("#navigation .active").removeClass("active");
button.addClass("active");
LoadSubNav(button);
}
});
I hope this provides sufficient context. I feel like the second selector is overkill (since it would only be run if the first selector succeeded), but I don't see how that would cause it to behave in this way.
Here's the snippet that seemed to be working in the other context:
function clearMenus(callback) {
$('[id$="_wrapper"]:visible:not(:animated)').hide("blind", 500, function() {
$('[id^="edit_"]:visible:not(:animated)').hide("slide", 200, function() {
callback();
});
});
}
Here, the animations queue instead of interrupt each other, but it occurs to me that the selector still doesn't seem to be working - the animations and associated loading events shouldn't be running at all, because the selectors should fail. While the queueing is nice behavior for animations to display, it made me realize that I seem to have never gotten this selector to work. Am I missing something?
Sometimes it's helpful to use .stop() and stop the current animation before you start the new animation.
$("#center_content").stop().hide("blind", 500, function () {});
Really depends on how it behaves within your environment. Remember that .stop() will stop the animation as it was (eg. halfway through hiding or fading)
I don't know if I understand it correctly, but if you want to make sure the user doesn't trigger the menu animation again while it's currently animating(causing it to queue animations and look retarded, this works and should help. I use an if-statement. And before any mouseover/off animation I add .stop(false, true).
$('whatever').click(function(){
//if center_content is not currently animated, do this:
if ($("#center_content").not(":animated")) {
$(this).hide(etc. etc. etc.)
}
//else if center_content IS currently animated, do nothing.
else {
return false;}
});
another example i found elsewhere:
if($("#someElement").is(":animated")) {
...
}
if($("#someElement:animated").length) {
...
}
// etc
then you can do:
$("#showBtn").attr("disabled", $("#someElement").is(":animated"));
Is there a script that will jump the page to the horizontal end.
A user can press "Home" and "End" on the keyboard to jump to the top and bottom of the webpage, but what about right and left?
How do I spare the user of the inconvenience of having to scroll to the far, far depths of the x scroll
Horizontal scroll is a somehow unfrequent situation, as naturally the browser will try to vertical scroll unless unresizable elements really overflow the visible area; I will thus assume you are more in an explicitly-horizontal design such as one of these: http://webdesignledger.com/inspiration/40-of-the-best-horizontal-scrolling-websites
In any case, the basic is the same: catch some key* event, and do what you want.
Catch the event and launch your scroll function:
document.body.addEventListener('keydown', scrollfct, true);
First caveat: 'keypress' will not catch special characters such as up/down etc., so use 'keydown' or 'keyup'
Now the scroll function:
function scrollfct(e) {
console.log(evt.keyCode); /* this will debug that your function is being called, and will help you get the keyCodes you want. Remove in production :-) */
var HOME_LEFT = 33; //HOME
var HOME_RIGHT = 34; //END
if (e.keyCode == HOME_LEFT) {
window.scroll(0,0);
};
if (e.keyCode == HOME_RIGHT) {
window.scroll(document.body.scrollWidth,0);
}
}
For window.scroll doc: https://developer.mozilla.org/en/Window.scroll
Second caveat: to be fully cross-browser, you'll have to do some homework.
If you want to deal with mousewheel too, or want some smooth scroll, check this out: http://paulicio.us/items/view/24/horizontal-page-scrolling-using-javascript or with jQuery: http://tympanus.net/codrops/2010/06/02/smooth-vertical-or-horizontal-page-scrolling-with-jquery/ OR just use HTML5 CSS Transitions.
Normally I'd say, pagination would save the user from scrolling all over the place, but there are a couple other techniques. You could include a "right" button that links to the ID of something at the right of the page. That would jump them there immediately. That would look like this
Goto the Right
. . .
<div id="overtotheright"> . . . </div>
Or in javascript, the following should work.
window.scrollTo(document.body.scrollWidth, 0);