Track scroll position according to visible section - javascript

I am having some trouble tracking the scroll position. I am trying to set a variable according to what section is visible.
My html looks like this
<body>
<div id="wrapper">
<div class="main">
<section id="one"><h2>BLA BLA</h2></section>
<section id="two"><h2>MJALLO!</h2></section>
<section id="three"><h2>MJALLO!</h2></section>
<section id="four"><h2>MJALLO!</h2></section>
<section id="five"><h2>MJALLO!</h2></section>
</div>
</body>
As said, i am trying to track the $(document) position and match it with a section id. I have for this the following jQuery
$(document).ready(function () {
var window = $(window);
var view = "";
if (window.scrollTop == $("#one").offset().top)
{view = "1";}
else if (window.scrollTop == $("#two").offset().top)
{view = "2";}
else if (window.scrollTop == $("#three").offset().top)
{view = "3";}
else if (window.scrollTop == $("#four").offset().top)
{view = "4";}
else if (window.scrollTop == $("#five").offset().top)
{view = "5";}
});
The section are styled as full frame blocks but i can't get any reaction on this if statement.
I am new to jQuery and js so a bit explanation would be appreciated ;)
Thanks in advance.

You need to wrap the ifs in a "on scroll" function:
$( document ).scroll(function() {
if(....)
});
https://api.jquery.com/scroll/

Related

how to get the current viewing div/div(s) in view port with jquery

is there any way i can get the current visible div in the view port from jquery/js?
Suppose my html page is like this:
<html>
<body>
<div id = "bodyDiv">
<div id="div1">div1 div content</div>
<div id="div2">div2 div content</div>
<div id="div3">div3 div content</div>
<div id="div4">div4 div content</div>
<div id="div5">div5 div content</div>
<div id="div6">div6 div content</div>
<div id="div7">div7 div content</div>
<div id="div8">div8 div content</div>
<div id="div9">div9 div content</div>
</div>
</body>
</html>
Suppose div3, div4 and div5 are in view port but i dont know about it. Is there any way i can get that info from jquery or from JS?
It's rare I plug one of my own libraries but I wrote one a while back that seems to do what you need. It's used in production so it should be reliable.
First of all you give your HTML elements a couple of classes:
<div id="div1" class="gocek pct-50">div1 div content</div>
<div id="div2" class="gocek pct-50">div2 div content</div>
<div id="div3" class="gocek pct-50">div3 div content</div>
gocek registers the element with the library (it's called gocek.js). pct-50 tells gocek to notify you when the element becomes at least 50% visible (or invisible, as required). You can change this percentage to anything you like; so to check if an element is fully visible (or invisible), you'd use pct-100.
Then the JavaScript:
gocek.on('visible', 'div', () => alert('callback')); //<-- all DIVs
gocek.on('visible', '#div3', () => alert('callback')); //<-- specific DIV
Should you want to listen for invisibility rather than visibility, you can change the first param to 'hidden'.
Here's a fleshed-out Fiddle and here's the unminified source code.
I regret that there's no proper documentation for it currently, but the Fiddle should guide you enough.
You can create a helper to add or remove a class like this
function findAll(selector, callback) {
//let nodesArray = Array.prototype.slice.call(document.querySelectorAll(selector));
let nodesArray = Array.from(document.querySelectorAll(selector));
if (typeof callback == "function") {
callback(nodesArray);
} else {
return nodesArray;
}
}
function intoViewport(elements, classNames, callback) {
findAll(elements, function(els) {
document.addEventListener("scroll", intoView, false);
window.addEventListener('resize', function() {
intoView();
});
function intoView() {
els.forEach(function(el) {
var rect = el.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
// Only completely visible elements return true:
//var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
// Partially visible elements return true:
var isVisible = elemTop < window.innerHeight && elemBottom >= 0;
if (isVisible == true && typeof callback == "function") {
el.classList.add(classNames);
callback(el);
} else {
el.classList.remove(classNames)
}
})
}
})
}
//intoViewport(".color", "active", function(e) { console.log(e)})

Efficient jQuery navbar?

I'm trying to make a simple navigation bar in HTML/jQuery and have managed to make a working implementation. Each tab is supposed to, when clicked, display the appropriate content section. (NOTE: all 's are display = none by default. the "active" class sets this value to "block")
I've been doing a bit of reading about efficiency concerns with Javascript and jQuery and really want to start making it a good habit of writing efficient code from the beginning as opposed to always having to come back to everything.
Is there a more efficient way of doing what the code I have below does? I know that constant calls to the DOM can be expensive, but I'm not entirely sure if I can change that in this scenario.
Any advice regarding how this example could be better would be great. General performance tips for jQuery/Javascript would also be greatly appreciated!
index.html
<div id="container">
<nav>
Home
About
Careers
Contact
Lasers
</nav>
<section id="home" class="active">
This is the home section!
</section>
<section id="about">
This is the about section!
</section>
<section id="careers">
This is the careers section!
</section>
<section id="contact">
This is the contact section!
</section>
<section id="lasers">
This is the lasers section!
</section>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="./app.js"></script>
app.js
$(document).ready(function() {
$('a').click(function() {
var view = $(this).data("content");
var curr = $("#"+view).attr("class");
if (curr !== "active") {
$(".active").toggleClass("active");
$("#"+view).toggleClass("active");
}
event.preventDefault();
})
});
What about
$(document).ready(function () {
//cache the sections
var $setions = $('#container > section');
$('a').click(function () {
var view = $(this).data("content");
//cache the target
var $view = $("#" + view);
//use hasClass to check whether the target is already active if so do nothing
if (!$view.hasClass('active')) {
//remove active class from other sections
$setions.filter(".active").removeClass("active");
//add active class to target
$view.addClass("active");
}
event.preventDefault();
})
});
I would do something like this:
var section = $("section");
$("nav a").on("click", function () {
section.removeClass("active");
$("#" + $(this).data("content")).addClass("active");
});
Less code + you're caching your sections.
Demo here:
http://jsfiddle.net/a75p8/
I think you're doing too much work with the data-content. How about something like this?
$(document).on('click','nav a',function(){
$('section').hide(); //or removeClass
var tmp_div = $(this).index(); // declaring a variable
$('nav a').eq(tmp_div).show(); // or addClass
});

Change Div Size dynamically

In my code, I've got 4 divs aligned inline.
What I want is, on clicking any div, it resizes to fill the space of all 4 divs (width:1000px)
and hides the other divs.
And on reclicking the div, it'll resize to the original dimensions.
This is what i've done till now.
<div class="gallery-image-replenish" id="bloc2" onclick="document.getElementById('bloc2').style.width = '980px'">
</div>
As of now, on click this resizes the div below the other divs. I know there's a method to hide the other divs, but I don't know how to do that.
With this kind of HTML:
<div class="gallery-image-replenish" id="bloc1"></div>
<div class="gallery-image-replenish" id="bloc2"></div>
<div class="gallery-image-replenish" id="bloc3"></div>
<div class="gallery-image-replenish" id="bloc4"></div>
you can use this kind of JS:
var handler = function(e){
e.target.style.width = "1000px";
for (j = divs.length; j--; ) {
if (divs[j].id != e.target.id) {
divs[j].style.display = "none";
}
}
}
var divs = document.getElementsByClassName('gallery-image-replenish'); //array of divs
var div;
for (i = divs.length; i--; ) {
div = divs[i];
div.addEventListener('click', handler);
}
Is it possible to use jQuery (jquery.com) on your project?
Because it would save a lot of code (and make it more readable!).
It would look like this (not tested, but probably works :P):
<div id="bloc1" class="gallery-image-replenish">1</div>
<div id="bloc2" class="gallery-image-replenish">2</div>
<div id="bloc3" class="gallery-image-replenish">3</div>
<div id="bloc4" class="gallery-image-replenish">4</div>
<script>
jQuery(document).ready(function(){
var galleryElements = $('.gallery-image-replenish');
galleryElements.click(function(){
var clickedElement = $(this);
if (clickedElement.hasClass('expanded')) { // if it has the class expanded, remove it (and show other elements again)
clickedElement.removeClass('expanded');
galleryElements.show();
} else { // if it has not got the expanded css class hide other and add class to expanded
galleryElements.not(clickedElement).hide(); // hide every other div
$(this).addClass('expanded'); // add stylesheet class for the new bigger width
}
});
});
</script>
The pure javascript way to hide an element is:
document.getElementById('otherdiv1').style.display = 'none';
Following is a solution which uses a common javascript function to perform what you want:-
<div class="gallery-image-replenish" id="bloc1" onclick="manageDivs(this.id)"> </div>
<div class="gallery-image-replenish" id="bloc2" onclick="manageDivs(this.id)"> </div>
<div class="gallery-image-replenish" id="bloc3" onclick="manageDivs(this.id)"> </div>
<div class="gallery-image-replenish" id="bloc4" onclick="manageDivs(this.id)"> </div>
<script type="text/javascript">
function manageDivs(divId)
{
document.getElementById(divId).style.width = '980px'";
//to hide rest of the divs
for(i=1;i<=4;i++)
{
if(divId!='bloc'+i)
document.getElementById('bloc'+i).style.display = 'none';
}
}
</script>
This is a simple exemple ,
var activ = false;
$('.aligned').live('click',function(){
if(!$(this).hasClass('actif')) {
$('.aligned').css('width','0');
$('.aligned').removeClass('actif');
$(this).css('width','1000px');
$(this).addClass('actif');
} else {
$('.aligned').css('width','250px');
}
});
you can use jQuery animate for more visual effect

How do I get DIV to disappear when another DIV is clicked?

I've got the following code that works great! When I click Link 1, the DIV content appears. When I click it again, it disappears. If I click Link 1 again, the DIV content appears again. If I click Link 2 this time, the content appears along with Link 1 content. I want Link 1 to disappear if another DIV link is clicked. I don't want to have to turn that content off before turning another one on. How do I make a DIV disappear after another one is clicked?
Javascript:
function show(ele) {
var srcElement = document.getElementById(ele);
if(srcElement != null) {
if(srcElement.style.display == "block") {
srcElement.style.display= 'none';
}
else {
srcElement.style.display='block';
}
}
return false;
}
DIV:
FIRST LINK
SECOND LINK
<div id="link1" style="display:none">
<p>Link 1 Content Displayed</p>
</div>
<div id="link2" style="display:none">
<p>Link 2 Content Displayed</p>
</div>
I don't want to change the way I'm doing this, I feel like there's a simple solution, I just can't figure it out! Any help is appreciated.
Another, better answer would be to use jQuery, because it lets you write better javascript without having to worry about whether IE is going to break.
include this tag in the head:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
Javascript:
function show( elem )
{
$('.dynamic_link').hide();
$('#'+elem).show();
}
HTML:
FIRST LINK
SECOND LINK
<div id="link1" class="dynamic_link" style="display:none">
<p>Link 1 Content Displayed</p>
</div>
<div id="link2" class="dynamic_link" style="display:none">
<p>Link 2 Content Displayed</p>
</div>
Javascript (modified):
function show(ele) {
var links = ['link1','link2'];
var srcElement = document.getElementById(ele);
var doShow = true;
if(srcElement != null && srcElement.style.display == "block")
doShow = false;
for( var i = 0; i < links.length; ++i ) {
var otherElement = document.getElementById(links[i]);
if( otherElement != null )
otherElement.style.display = 'none';
}
if( doShow )
srcElement.style.display='block';
return false;
}
working example: http://jsfiddle.net/vDKmA/

Jquery slide down only if not already visible

I have a simple problem using Jquery. I want to display detailed information under menu headings, but the interface isn't so smooth. After a few hours of trying some things out, I've come back to the beginning to see if there is a simple answer
Look at this example
Two problems:
If you mouse over several categories at once to get to the category you want, the animation still runs through all of the other animations instead of stopping the other ones and only animating the one that the mouse is currently hovered over.
If you mouse over a category that is already open, it still runs the animation, but I only want the animation to run if the content is not already visible. Is there a simple if statement that can do this?
$('.content').hide();
var $elms = $('.fruit, .vegetable, .dairy');
$elms.hover(function() {
var $content = $(this).next('.content');
$content.stop(1, 1).slideToggle(400);
});
http://jsfiddle.net/elclanrs/GBkMB/1/
Edit:
To prevent the content from sliding back up you can nest the divs like so:
<div class="fruit">fruit
<div class="content fruit_types">apple<br/>bannana<br/>orange</div>
</div>
<div class="vegetable">vegetable
<div class="content vegetable_types">celery<br/>lettuce<br/>cucumber</div>
</div>
<div class="dairy">dairy
<div class="content dairy_types">milk<br/>cheese<br/>butter</div>
</div>
jQ:
$('.content').hide();
var $elms = $('.fruit, .vegetable, .dairy');
$elms.hover(function() {
var $content = $(this).children('.content'); //<-`children()` not `next()`
$content.stop(1,1).slideToggle(400);
});
Example: http://jsfiddle.net/elclanrs/GBkMB/5/
I've edited your fiddle now to look like this. Should give you an idea of what you want to move forward:
http://jsfiddle.net/GBkMB/4/
$("body").on("hover", ".fruit, .vegetable, .dairy", function(event){
if(event.relatedTarget != $(this).next(".content")[0]){
if(event.type == "mouseenter"){
$('.content').slideUp('slow');
$('.'+$(this).attr("class")+'_types').slideDown('slow');
}else if(event.type == "mouseleave"){
$('.content').slideUp('slow');
}
}
});
$("body").on("mouseleave", ".content", function(event){
if(event.relatedTarget != $(this).prev("div")[0]){
$(this).slideUp('slow');
}
});
or: http://jsfiddle.net/GBkMB/6/ #elclanrs answer ++
$('.content').on("mouseleave", function(event){
if(event.relatedTarget != $(this).prev("div")[0]){
$(this).slideUp('slow');
}
});
var $elms = $('.fruit, .vegetable, .dairy');
$elms.on("hover", function(event) {
var $content = $(this).next('.content');
if(event.relatedTarget != $content[0]){
$content.stop(1,1).slideToggle(400);
}
});

Categories