Change class of item when scrolled to - javascript

I have a nav set up that when a link is clicked, the page scrolls down to the corresponding item in a list, changing the class of the link when the item is reached.
<nav>
one
two </nav>
<ul>
<li id="one"></li>
<li id="two"></li>
</ul>
Here is a rather crude example
http://jsfiddle.net/FSk5Q/1/
I would also like to change the background colour of the item once it is reached (preferably fading to a new colour), and then restore it's original class when another item is scrolled to, then changing the next item's class.
I need this to happen when clicked to AND scrolled to, so the :target option is not really ideal.
Many thanks for an advice. Not too good in the js department.

Hopefully this can at least get you started. What I have done is check that the offset top is less than the document's scroll top (you could also do something like if it's within X number of pixels).
The color fading can be done with CSS3 transitions.
$(document).on('scroll', function () {
$("li").each(function () {
if ($(this).offset().top <= $(document).scrollTop()) {
$("li").removeClass('highlight');
$(this).addClass('highlight');
}
else {
$(this).removeClass('highlight');
}
});
});
http://jsfiddle.net/FSk5Q/6/

I did a fixed version based on Explosion Pills' one. Hope it's what you wanted.
$(document).on('scroll', function ()
{
$("nav a").removeClass('highlight'); // reset all menu items
temp = $();
$("li").each(function (i) // for each content blcok (you schould give them a class)
{
if ($(this).offset().top <= $(document).scrollTop()) // if it's position is above/at the page top
{
temp = $("nav a:nth-child("+(i+1)+")");
}
});
temp.addClass('highlight');
});
http://jsfiddle.net/maxmeuten/FSk5Q/8/

Related

Reinstate hover rules after click

I am using the below script to hide/show my main nav menu items. You can see it live here: http://205.134.239.12/~artscr6/artscrush/#!
One part of my menu uses down arrows (represented using font awesome with the <i> tags) and when the user hovers over the menu item, the arrow appears. This works in the initial state, but once the user clicks one of the menu items to show the flyout, the hover effect no longer works to show the arrows.
What would I need to add to keep that hover effect happening, but still keep the current behavior as well?
/Remove the link elements from the main nav top level
$('.menuItem a').attr('href', '#!');
//Show the down arrows on hover
$('menuItem').hover(function() {
$(this).find('i').css('opacity', '1');
})
//Once menu is clicked
$('.menuItem').click(function() {
//Reset
menuReset();
//Find the correct flyout
var item = $(this).attr('id');
var id = item.substring(item.indexOf("_") + 1);
var findFlyout = '#acFly_' + id;
//Make this item active
$(this).addClass('active');
//Bumps the current down arrow down a bit and shows it
$(this).find('i').css('opacity', '1');
$(this).find('i').css('top', '7px');
//Show the flyout
event.stopPropagation(); //This prevents dom from overriding us
$(findFlyout).toggle();
//Prevent clicks on the current menu from hiding the flyout
$(findFlyout).click(function(){
event.stopPropagation();
})
})
//Hide the menu when the user clicks anywhere
$(document).click( function(){
menuReset();
})
function menuReset() {
$('.flyMenu').hide();
//Resets the down arrows to orig position and hidden
$('.menuItem').find('i').css('opacity', '0');
$('.menuItem').find('i').css('top', '0px');
$('.menuItem').removeClass('active');
}
//Show the down arrows on hover
$('menuItem').hover(function() { // Shouldn't this be .menuItem instead?
$(this).find('i').css('opacity', '1');
})
Also, in the css file on the link you gave me I find the following:
#menu .ul .li:hover i{
opacity: 1;
}
I don't think ul and li are classes, so why is there a . ?
EDIT: Oh, I see now. You named your divs ul and li. :)

jQuery Accordion | Open first element on pageload & active state confusion

I am using the Javascript below to animate an accordion (it's a slightly modified variant of the one explained here: http://tympanus.net/codrops/2010/04/26/elegant-accordion-with-jquery-and-css3/.
Now I wanted to have the first element to be open on pageload, so I figured I just give it some sort of extra-class via Javascript (and define that .active state via CSS) to have it open up.
This worked, however if I hover over any but the first-element with said .active class, the first element keeps its state, and stays open until I hover over it at least once.
So, what I want is: the first element of my accordion is open and collapses if the user hovers over any of the elements that are not the first. I think I need to add a line in the hover function to either take the class away of the first element or to give the new element the active state, but I don't know how to do it and keep breaking the thing.
<script type="text/javascript">
jQuery(function() {
activeItem = jQuery("#accordion li:first");
jQuery(activeItem).addClass('active');
jQuery('#accordion > li, #accordion > li.heading').hover(
function () {
var jQuerythis = jQuery(this);
jQuerythis.stop().animate({'height':'280px'},500);
jQuery('.heading',jQuerythis).stop(true,true).fadeOut();
jQuery('.bgDescription',jQuerythis).stop(true,true).slideDown(500);
jQuery('.description',jQuerythis).stop(true,true).fadeIn();
},
function () {
var jQuerythis = jQuery(this);
jQuerythis.stop().animate({'height':'40px'},1000);
jQuery('.heading',jQuerythis).stop(true,true).fadeIn();
jQuery('.description',jQuerythis).stop(true,true).fadeOut(500);
jQuery('.bgDescription',jQuerythis).stop(true,true).slideUp(700);
}
);
});
</script>
Looks like this is happening because each accordion item has its own hover event that takes care of its own animation. You can refactor the code slightly to make this easier to understand and reuse:
var activeItem = jQuery("#accordion li:first");
jQuery('#accordion > li, #accordion > li.heading').hover(
function () { hoverMe(jQuery(this)); },
function () { unhoverMe(jQuery(this)); }
);
//This gets called when cursor hovers over any accordion item
var hoverMe = function(jQuerythis) {
//If the first item is still active
if (activeItem) {
contract(activeItem); //...Shrink it!
activeItem = false;
}
//Expand the accordion item
expand(jQuerythis);
};
//This gets called when cursor moves out of accordion item
var unhoverMe = function(jQuerythis) {
contract(jQuerythis);
};
//I have moved the hover animation out into a separate function, so we can call it on page load
var expand = function(jQuerythis) {
jQuerythis.stop().animate({'height':'280px'},500);
jQuery('.heading',jQuerythis).stop(true,true).fadeOut();
jQuery('.bgDescription',jQuerythis).stop(true,true).slideDown(500);
jQuery('.description',jQuerythis).stop(true,true).fadeIn();
};
//I have moved the unhover animation out into a separate function, so we can contract the first active item from hoverMe()
var contract = function() {
jQuerythis.stop().animate({'height':'40px'},1000);
jQuery('.heading',jQuerythis).stop(true,true).fadeIn();
jQuery('.description',jQuerythis).stop(true,true).fadeOut(500);
jQuery('.bgDescription',jQuerythis).stop(true,true).slideUp(700);
};
//Now expand the first item
expand(activeItem);
I have put together a simplified version demonstrating the logic. Please let me know how you get on.

selecting :last-child using jquery

I have a carousel and each anchor in the menu area is linked to selected slide and when the anchor in the menu is selected it receives a .active class.
Ex: link 1 = slide 1.
I tried to add a stop button instead of next when the carousel reaches the last slider.
<nav class="meniu">
Slide 1
Slide 2
Slide 3
</nav>
<div id="slider">
<ul>
<li>Slide 1</li>
<li>Slide 2</li>
<li>Slide 3</li>
</ul>
</div>
This is the script that i tried to add
if ($('.meniu a:last-child').hasClass('active')){
//change button arrow to stop sign
}
Here is the fiddle - http://jsfiddle.net/G7P46/1/
Okay, so here's your problem.
When just using the back and forth buttons, you get the element with the 'active' class, and remove the class then add it to the next sibling. Here's the problem. If you only use the buttons, no anchor ever actually gets set to active. So the jquery selector looking for active returns 0. There's no "next" so it can't check to see if the last element has active.
Now, if you click on a link, THEN use the buttons, it works because at least one anchor has been set to "active".
Here is a working fiddle.
http://jsfiddle.net/G7P46/2/
I updated the gonext function
function goNext() {
if (decount != counter) {
$('#slider ul').animate({
left: '-=' + $('#slider').width()
}, 800, 'swing', function () {
});
if ($('.active').length == 0) {
$('.meniu a:first-child').addClass('active');
}
$('.active').removeClass('active').next().addClass('active');
if ($('.meniu a:last-child').hasClass('active')) {
console.log('change button');
}
decount++;
window.location.hash = decount;
}
}
Notice that I add a check to see if there is any anchor set to active. If not, I set the first child to active. I also added the change button if statement. It now gets hit.
Also, I updated the click event
$('.meniu a').on('click', function () {
var goTo = this.id * -$('#slider').width() + $('#slider').width();
$('#slider ul').animate({
left: goTo
}, 800, 'swing', function () {});
$('.active').removeClass('active');
$(this).addClass('active');
decount = this.id;
window.location.hash = this.id;
if ($('.meniu a:last-child').hasClass('active')) {
console.log('change button');
}
});
Now it checks the last anchor there to.
Edit: I updated the fiddle again to have the actual button changing functionanlity
http://jsfiddle.net/G7P46/3/
try this :
if ($('.meniu a:last').hasClass('active')){
//change button arrow to stop sign
}
I hope it will help.

jQuery - nth child and slider problem?

There is a generic image slider (nivo image slider) used on the charity pages that contains 7 slides, each slide is a different charity. I have used some jQuery so that when you are on a charities detail page, that specific charities slide shows up first in the slider queue; instead of it just looping from the start of the slider queue and showing a non-relevant charity. Basically looks at the URL and matches to the href in the slider link and adds a class then moves to the top of the link etc...
For example, these 2 work fine...
http://test.clothesaid.co.uk/partner-charities/yorkshire-cancer-centre/
http://test.clothesaid.co.uk/partner-charities/nspcc/
...they load their respective charities slider. However...
http://test.clothesaid.co.uk/partner-charities/papworth-hospital-charity/
...which is the oldest entry and at the bottom of the list won't load it's respective slider and just shows the slider list in it's normal order as the jQuery has not kicked in.
The charities are added in date order with the newest charity at the top of the list and the oldest charity at the bottom of the list. The jQuery works fine on all charities apart from whatever charity is at the bottom of the list, it just won't kick in. I'm sure it's something to do with the 'clone' slide that the Nivo slider uses and something to do with the :nth child in jQuery but I just can't work it out. That's the only thing that would make sense as the date order of the charities is the only thing that is changing. You can see the stack of charity logos on the right hand side of the page, that is the date order, with the oldest at the bottom. It's always the oldest one (at the bottom of the list) that won't work.
I'm basically stuck!
HTML
<ul id="slider1">
<li class="panel cloned">Example</li>
<li class="panel hello">Example</li>
<li class="panel">Example</li>
<li class="panel">Example</li>
<li class="panel">Example</li>
<li class="panel cloned">Example</li>
</ul>
jQuery
var url = window.location.toString();
$('#slider1 li.panel a').each(function(){
var myHref= $(this).attr('href');
if( url == myHref) {
$(this).closest("li").addClass('hello').insertAfter("#slider1 li:nth-child(1)");
return false;
}
});
What's happening is that 'papworth-hospital-charity' is the first in the list of li and insertAfter will try to insert it after himself which is not working
I suggest that you check the index of the li before moving it (you are moving the target li to the 2nd position right?)
var url = window.location.toString();
$('#slider1 li.panel a').each(function(index){
var myHref= $(this).attr('href');
if( url == myHref) {
$(this).closest("li").addClass('hello')
if(index==0){
$(this).closest("li").insertAfter("#slider1 li:nth-child(2)");
}else{
$(this).closest("li").insertAfter("#slider1 li:nth-child(1)");
}
return false;
}
});
or use anythingSlider ability to show slides by index:
var url = window.location.toString();
$('#slider1 li.panel a').each(function(index){
var myHref= $(this).attr('href');
if( url == myHref) {
$('#slider1').anythingSlider(index);
return false;
}
});
$(document).ready(function() {
var url = window.location.toString();
$('#slider1 li.panel a').each(function(){
var myHref= $(this).attr('href');
if( url == myHref) {
$(this).closest("li").addClass('hello').insertAfter("#slider1 li:nth-child(1)");
return false;
}
});
};

Simple Ticker (jQuery)

<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
I'd like to show only one li at a time using slide effect, thats it. I'd like to avoid using plugins for something as simple as this.
Thanks in advance for your help.
i have made something simple up for you (based on your description), just to point you in the right direction:
check it out here:
http://jsfiddle.net/meo/ACenH/234/
function slider(container, delay){
$container = $(container) // select the container elements and store them in a variable
if ( !$container.length ){ return fasle; } // checks if the slider exists in your dom. if not the function ends here...
var slides = $container.length, // gives back the total LI's you have
slide = 0 // set the actual li to show
setInterval(function(){ // set a Interval for your main function
if (slide == slides - 1) { // if the actual slide is equal the total slides (-1 because eq is 0 based and length gives back the number of elements in the jQuery object) the slide counter is set to 0
$container.slideDown(); // and all slides a shown again
slide = 0;
} else {
$container.eq(slide).slideUp(); //slides the selected slide up i think you could think of a solution with .next() instead of eq()
slide++; // slide counter +1
}
}, delay)
}
slider('ul > li', 2000); // call your slider function
Your question already mentions jquery as the javascript framework of choice. The best place you can start is the jquery docs on hiding:
http://api.jquery.com/hide/
and sliding:
http://api.jquery.com/slideUp/
http://api.jquery.com/slideDown/
http://api.jquery.com/slideToggle/

Categories

Resources