We use some jQuery to make our navigation sticky from some point on the page and to add an active class to sections on the page. Currently the active class is added to the a class inside the li. But I want to add this to the li instead of the a href.
How can I achieve this?
Code:
<script>
$j(window).scroll(function(){
var sticky = $j('.menu-header-product'),
scroll = $j(window).scrollTop();
var elementOffset=jQuery("#productnav").offset();
if (scroll >= elementOffset.top - 57) sticky.addClass('sticky');
else sticky.removeClass('sticky');
});
$j(window).scroll(function(){
var sticky = $j('.content'),
scroll = $j(window).scrollTop();
var elementOffset=jQuery("#productnav").offset();
if (scroll >= elementOffset.top - 57) sticky.addClass('sticky');
else sticky.removeClass('sticky');
});
$j(document).ready(function () {
$j(document).on("scroll", onScroll);
$j('a[href^="#"]').on('click', function (e) {
e.preventDefault();
$j(document).off("scroll");
$j('li').each(function () {
$j(this).parent().removeClass('active');
})
$j(this).parent().addClass('active');
var target = this.hash;
$jtarget = $j(target);
$j('html, body').stop().animate({
'scrollTop': $jtarget.offset().top - 120 /**just subtract the height of the fixed html part */
}, 500, 'swing', function () {
window.location.hash = target;
$j(document).on("scroll", onScroll);
});
});
});
function onScroll(event){
var scrollPosition = $j(document).scrollTop();
$j('nav li').each(function () {
var currentLink = $j(this);
var refElement = $j(currentLink.attr("href"));
if (refElement.position().top - 125 <= scrollPosition && refElement.position().top - 125 + refElement.height() > scrollPosition) {
$j('nav ul li a').parent().removeClass("active");
currentLink.parent().addClass("active");
}
else{
currentLink.parent().removeClass("active");
}
});
}
</script>
You can use jQuery's parent selector. So
$j(this).addClass('active');
becomes
$j(this).parent().addClass('active');
You would also need to change the selector $j('a') to $j('li'). I would recommend filtering to only lis in your navigation, i.e. $j('nav li'). Finally, you'd have to update the onScroll event similarly.
Related
I have this HTML page:
https://shibbir.dev/demo-work/html-one-page/
On this page, you will see a second sticky sidebar whose title is "Credit ipotecar"
In this sidebar, I have a few li elements. If you click on any li element you will scroll down to the corresponding div on the right side.
But the problem is I can see only a few li elements on the sidebar thus I can't click on other li elements to see another corresponding div.
So, how can I make the last li element scroll up once I click on the last viewable li element?
Something like this example:
https://discount.ro/cataloage/pepco-ro/cupon-de-reducere-pepco-colectia-de-rochii-din-bumbac-organic-02-15-iunie-2022-16353/#section11
My JS Code:
(function ($) {
"use strict";
$(document).ready(function () {
$(window).scroll(function () {
var scrollBar = $(this).scrollTop();
var navigate = document.querySelector(".sh-body-container div").offsetTop
$(".sh-body-container div").each(function (index) {
var elTop = $(this).offset().top;
var elHeight = $(this).height();
if (scrollBar >= elTop - navigate && scrollBar < elTop + elHeight) {
$(".sh-body-sidebar ul li").eq(index).addClass("sidebarActive").siblings().removeClass("sidebarActive");
}
});
});
$(".sh-see-more").click(function(e){
e.preventDefault();
var that = $(this);
that.prev(".sh-see-more-details").toggleClass("is-active");
});
$(".hide-show").click(function(e){
e.preventDefault();
var that = $(this);
var plusSign = that.children("a").text();
if( "+" == plusSign ) {
that.children("a").text("-");
} else {
that.children("a").text("+");
}
var faq = that.next(".sh-faq-answer").toggleClass("faq-active");;
});
$(".sh-mobile-calculator-icon").click(function() {
$(".sh-calculator").addClass("show-calculator");
$(".show-filter").show();
$(".show-filter a").click(function() {
$(".sh-calculator").removeClass("show-calculator");
});
});
});
})(jQuery);
I am trying to implement some code I found on SO which adds the class "active" when the matching div is on the page. So scroll down, get to the div and the active class is added to the correct menu item.
Currently, it is working but with some hitches, right now it's applying the active class at the bottom of the div, not when it hits the top. So I think I am at a bit of a loss.
Here is the current JS:
<script>
// Cache selectors
var lastId,
topMenu = $("#nav"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
});
</script>
You can view the original js here on jsfiddle but mine is not acting like this one: http://jsfiddle.net/mekwall/up4nu/
The issue I see: on fiddle it works but the divs on fiddle have no height just a top value, if you add height like any div would have it causes the issue.
Found a far better solution to what I had above and I made a codepen for it.
https://codepen.io/LukeD1uk/pen/MVeGQW
$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 100) {
$('section').each(function(i) {
if ($(this).position().top <= windscroll - 0) {
$('nav li.active').removeClass('active');
$('nav li').eq(i).addClass('active');
}
});
} else {
$('nav li.active').removeClass('active');
$('nav li:first').addClass('active');
}
}).scroll();
I have a page in Magento with all the categories and products listed. On top I have a menu with the categories and the items you scroll by must get a class so I can change the color.
I have this script at the moment:
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('ul.nf-category-menu li a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('ul.nf-category-menu li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
But the class is changing from div to div to soon, can I give some offset so the class will be added later?
Update:
It's no changing the "active" class to soon when te title is 150px away from the top, I would like to change the class around 80px from top.
Regards,
I already fixed it, it was quite simple after trying some things. This is how it was done:
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('ul.nf-category-menu li a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top+243 <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('ul.nf-category-menu li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
if (refElement.position().top had to be changed to: if (refElement.position().top+243 where 243 is the amount of pixels of the offset.
I'm new to jquery and have put together the following code to make a DIV appear after a set scroll-down amount. If scrolling back up, the DIV disappears. Optionally, once the DIV has appeared, there is a link to close it. This all works as intended, apart from that I only want the script to run once. At the moment if I scroll back up, the yellow box appears again. How can I ensure the box stays closed? As another option, could I integrate cookies or localStorage?
Many thanks! Russ.
Javascript:
$(function () {
var target = $(".box");
if ($(window).scrollTop() > 30) {
target.hide();
}
$(window).scroll(function () {
var pos = $(window).scrollTop();
if (pos > 30) {
target.stop(true, true).fadeIn('slow');
} else {
target.stop(true, true).fadeOut('slow');
}
});
$('a.close').click(function () {
$($(this).attr('href')).slideUp();
return false;
});
});
Here is the jsfiddle link to my code: jsfiddle link
You can remove the class to ensure the box stays enclosed with removeClass(). Or directly $(".box").remove() after your animation.
You can store this choice with cookie but if the client deletes his cookies, it's lost.
You can remove event scroll from window and for localStorage do something like that:
$(function () {
var target = $(".box");
if ($(window).scrollTop() > 30) {
target.hide();
}
$(window).scroll(function () {
var pos = $(window).scrollTop();
if (pos > 30) {
target.stop(true, true).fadeIn('slow');
} else {
target.stop(true, true).fadeOut('slow');
}
if(localStorage['noNotification'] == 'true'){
$(window).off('scroll');
}
});
$('a.close').click(function () {
$($(this).attr('href')).slideUp();
$(window).off('scroll');
localStorage['noNotification'] = 'true';
return false;
});
});
try this http://jsfiddle.net/AbwXu/4/
var notdisplayed=true;
$(function(){
var target = $(".box");
if($(window).scrollTop() > 30){
target.hide();
}
$(window).scroll(function(){
var pos = $(window).scrollTop();
if(pos > 30 && notdisplayed){
target.stop(true, true).fadeIn('slow');
} else {
target.stop(true, true).fadeOut('slow');
notdisplayed=false;
}
});
$('a.close').click(function() {
$($(this).attr('href')).slideUp();
notdisplayed=false;
return false;
});
Let's say we've got this HTML:
<div class="locationhash" data-position="0"></div>
<div class="locationhash" data-position="1000"></div>
<div class="locationhash" data-position="3000"></div>
<div class="locationhash" data-position="5000"></div>
<div class="locationhash" data-position="8000"></div>
where data-positions value, in normal conditions would equal to elements height from pages top in px.
Im retrieving elements with .locationhash, reading its data-position and pushing both values as an object into an array using this code. (works as intended, output in third code sample here)
var getSections = function() {
var pageSectionsArr = [];
var pageSections = (document).querySelectorAll('.locationhash');
Array.prototype.forEach.call(pageSections, function(section) {
var getSectionPos = section.getAttribute('data-position');
var pageSectionObj = {
pageSection : section,
pageSectionPos : getSectionPos
};
pageSectionsArr.push(pageSectionObj);
});
console.log(pageSectionsArr)
};
(function recalcSectionPos() {
$(window).resize(function() {
getSections();
});
})();
Output looks like this:
[ {div.locationhash, value of its data-position},
{div.locationhash, value of its data-position}, ... ]
Now i need to check on scroll wether current window.scrollTop() equals any of data-position values so:
$(window).scroll(function() {
var hFromTop = $(window).scrollTop()
//cant figure out what should i do next (jquery allowed)
});
Question: How could i check current window.scrolltop() against multiple values, while user is scrolling so i could make something happen when window.scroll top equals to a value
(I'm using this array because later im gonna read .locationhash's id in order to append it to url using location replace)
DEMO
$(document).ready(function () {
$(document).on("scroll", onScroll);
//smoothscroll
$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
$(document).off("scroll");
$('a').each(function () {
$(this).removeClass('active');
})
$(this).addClass('active');
var target = this.hash,
menu = target;
$target = $(target);
$('html, body').stop().animate({
'scrollTop': $target.offset().top+2
}, 500, 'swing', function () {
window.location.hash = target;
$(document).on("scroll", onScroll);
});
});
});
function onScroll(event){
var scrollPos = $(document).scrollTop();
$('#menu-center a').each(function () {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('#menu-center ul li a').removeClass("active");
currLink.addClass("active");
}
else{
currLink.removeClass("active");
}
});
}
I followed #tushar gupta's advice, also wrapped it in a function checking wether scrolling ended
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
var hFromTop = $(window).scrollTop();
$.each(pageSectionsArr, function(obj) {
console.log(this + 'is sparta')
if (~~this.pageSectionPos <= hFromTop && ~~this.pageSectionPos + this.pageSection.offsetHeight > hFromTop) {
//console.log(this.pageSectionPos)
var sectionsId = this.pageSection.id
//console.log(sectionsId)
window.location.replace('#/'+sectionsId)
};
});
}, 250));
});