Scroll child div while parent div is position sticky in vue JS - javascript

I have a use case for my landing page, where when user enters one of the <section> of the page, the section becomes fixed but the elements inside that <div> starts scrolling. Once the inner div is done scrolling the parent <section> should start scrolling as a normal section and should go away to the top with a scroll.
I've created a similar structure in the jsFiddle below. But not able to achieve the desired feature.
https://jsfiddle.net/8qm67ks9/2/
I wanted to achieve this behavior as presented on this website. Section SS below
HTML
... Other sections before
<section ref="stickyDiv" class="scroller py-sm-128">
<div class="">
<div ref="wrapper" #scroll="scrollerListener" class="wrapper-box">
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
</div>
</div>
</section>
... Other sections in the bottom
Vuejs
methods: {
...
listenBodyScroll(e) {
if (this.isMobile) {
return;
}
const stickyDiv = this.$refs.stickyDiv;
const wrapper = this.$refs.wrapper;
const dim = stickyDiv.getBoundingClientRect();
console.log(dim.y, dim.height, '---scrollTop');
if (dim.y <= 0) {
if (Math.ceil(dim.height) <= Math.abs(dim.y)) {
stickyDiv.style.position = 'relative';
stickyDiv.style.top = 'auto';
stickyDiv.style.height = 'auto';
wrapper.style.overflowY = 'hidden';
wrapper.scrollTop = wrapper.scrollHeight;
return;
}
wrapper.focus();
stickyDiv.style.position = 'sticky';
stickyDiv.style.top = '100px';
stickyDiv.style.height = '100vh';
wrapper.style.overflowY = 'auto';
}
},
scrollerListener({ target: { scrollTop, offsetHeight, scrollHeight, style } }) {
if (this.isMobile) {
return;
}
const stickyDiv = this.$refs.stickyDiv;
if ((Math.ceil(scrollTop) + offsetHeight) >= scrollHeight) {
stickyDiv.style.position = 'relative';
stickyDiv.style.top = 'auto';
stickyDiv.style.height = 'auto';
style.overflowY = 'hidden';
console.log('bottom!');
}
}
}
Vue direction v-scroll
Vue.directive('scroll', {
inserted(el, binding) {
const f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
});

There are no secret techniques in web development. Use your browser's inspect tool and check the website's HTML/CSS and see exactly how it works for yourself.
I did this myself and took some of the website's HTML and CSS and recreated a simple version you can see in this codesandbox
Basically, there are two divs of 50% width side by side that exist within the same parent div forcing them to be the same (very large) height. Once you scroll the parent div into view, the image container with position: sticky keeps it in the same relative screen position until you get to the bottom of its parent div where it will then scroll away with the rest of the parent div content.

Related

I am looking to have an image in navbar change to a different when a corresponding section on the page is in viewport

I have images in a navbar that change their src when the image hovered over using mouseover. I am looking to have that same hover effect on the image when a section is scrolled to in viewport that matches the id.
This is what I have attempted recently. The hover works fine, but the image doesn't seem to change when section is scrolled to.
One example in the navbar
<div class="number"><img class="ai" src="https://unsplash.com/photos/Z1wosLgwGT8" onmouseover="this.src='https://unsplash.com/photos/q98u_gIRs6I'" onmouseout="this.src='https://unsplash.com/photos/Z1wosLgwGT8'" alt="3"></div>
One div example with the id to match navbar link
<div class="test" id="1">
<div class="test" id="2">
<div class="test" id="3">
<div class="test" id="4">
The JS I have so far
const testDiv = document.querySelector("#3");
const aiImg = document.querySelector(".ai");
window.addEventListener("scroll", function() {
const viewportHeight = window.innerHeight;
const divTop = testDiv.getBoundingClientRect().top;
const divBottom = testDiv.getBoundingClientRect().bottom;
if (divTop <= viewportHeight && divBottom >= 0) {
aiImg.src = "https://unsplash.com/photos/q98u_gIRs6I";
}
});

simplifying a javascript click count menu controlling 3 individual dropdowns

I've got 3 individual slide down menu's at the top of my page.
Page Menu
Account dropdown
Cart Dropdown
I've created individual open and close functions for each one
function menu_open(){
document.getElementById("myNav_overlay").style.height = "100%";
document.getElementById("myNav").style.height = "100%";
$('.menu-link').text("menu_open");
}
function menu_close() {
document.getElementById("myNav_overlay").style.height = "0%";
document.getElementById("myNav").style.height = "0%";
$('.menu-link').text("menu");
}
function account_open(){
document.getElementById("myAccount_overlay").style.height = "100%";
document.getElementById("myAccount").style.height = "100%";
$('.account-link').text("person");
}
function account_close() {
document.getElementById("myAccount_overlay").style.height = "0%";
document.getElementById("myAccount").style.height = "0%";
$('.account-link').text("person");
}
function cart_open(){
document.getElementById("myCart_overlay").style.height = "100%";
document.getElementById("myCart").style.height = "100%";
$('.cart-link').text("shopping_cart");
}
function cart_close() {
document.getElementById("myCart_overlay").style.height = "0%";
document.getElementById("myCart").style.height = "0%";
$('.cart-link').text("shopping_cart");
}
and then 3 individual click count functions to determine if the menu needs to open or close.
$(function() {
var menuclickCount = 0;
var accountclickCount = 0;
var cartclickCount = 0;
$('.menu-link').click(function () {
if(menuclickCount%2==0){
//do when open
menu_open();
account_close();
cart_close();
}else{
//do when closed
menu_close();
}
clickCount++;
});
$('.account-link').click(function () {
if(accountclickCount%2==0){
//do when open
account_open();
menu_close();
cart_close();
}else{
//do when closed
account_close();
}
accountclickCount++;
});
$('.cart-link').click(function () {
if(cartclickCount%2==0){
//do when open
cart_open();
menu_close();
account_close();
}else{
//do when closed
cart_close();
}
cartclickCount++;
});
});
This seems rather large compared to what it has to be and seems like there may be a better/simpler way of doing it. But honestly not sure how this would typically be done.
Is it better to leave a setup like this as is where each one is controlled individually and manually closes the other? OR, is it better to combine these into a more robust, smaller function that still controls them as needed?
If it is better to combine into a simpler function, how would this be done to where it still opens and closes each dropdown section?
I took 1 working function and duplicated it to make this work as is. So now I'm curious to see how this compares to what is considered industry standard and practical.
The HTML is simple....
Menu content
<div id="myNav_overlay" class="overlay_background"></div>
<div id="myNav" class="nav-overlay">
<div class="overlay-content">
MENU
</div>
</div>
Account content
<div id="myAccount_overlay" class="overlay_background"></div>
<div id="myAccount" class="account-overlay">
<div class="overlay-content">
ACCOUNT
</div>
</div>
Cart content
<div id="myCart_overlay" class="overlay_background"></div>
<div id="myCart" class="cart-overlay">
<div class="overlay-content">
CART
</div>
</div>
Without getting into styling the example too much, using the wonder of jQuery, you can do this:
(1) On click, select all menu containers (class .ddown in my example)
(2) return all menu containers to their default height of zero (by removing the .showMenu class with its new height)
(3) for the clicked container only, apply a style that increases container height.
$('.ddown').click(function(){
$('.ddown').removeClass('showMenu');
$(this).addClass('showMenu');
});
.container{height:100px;}
.ddown{display:inline-block;width:100px;border:1px solid #ccc;overflow:hidden;}
.mnuTitle{height:20px;}
.mnuContent{height:0;background:white;}
.showMenu{height:100px;background:palegreen;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="container">
<div id="myNav" class="ddown">
<div class="mnuTitle">Menu</div>
<div class="mnuContent">
MENU CONTENT
</div>
</div>
<div id="myAccount" class="ddown">
<div class="mnuTitle">Account</div>
<div class="mnuContent">
ACCOUNT CONTENT
</div>
</div>
<div id="myCart" class="ddown">
<div class="mnuTitle">Cart</div>
<div class="mnuContent">
CART CONTENT
</div>
</div>
</div><!-- .container -->

Trigger play on video when two divs match up

I have created a way to scroll through divs, one has a menu and the others have divs with blanks but one has a video.
At the top of the page is a navigation menu that contains "next", "previous", "reload" and "start".
Those commands are warped in functions,
$("#next-item").on("click", function(){,
The page looks like this:
<div class="webcam-left">
<div class="bottom-panel">
<div class="center" id="content">
<div class="bottom-panel-post internal start"></div>
<div class="bottom-panel-post internal video-post"><video src="https://ia800606.us.archive.org/12/items/ACTV_News_open/ACTV_News_open.mp4"></video></div>
<div class="bottom-panel-post internal"></div>
</div>
</div>
</div>
<div class="nav-right nav-main">
<div class="rundown-panel">rundown</div>
<div class="rundown-items">
<div class="irl-today first"><div class="current">Welcome</div></div>
<div class="irl-today override">Category name</div>
<div class="irl-today">the end</div>
</div>
</div>
</div>
What I'm trying to do is when scrolling down the list, how do you trigger play on a video when a video is shown?
When scrolling down, I added classes to the divs that contain a video.
The left side has .override and the video side has .video-post.
I tried doing if hasClass() but it plays on the first click:
if ( $('.rundown-items').is('.override') ) {
if ($( '.bottom-panel-post' ).has('video')) {
$('video').trigger('play');
};
};
Working code - https://jsfiddle.net/openbayou/paonbxcL/8/
I figured it out, the problem was that it was looking for a class across all items and not each one individually so I added an .each function to look for a class on each individual div.
$(".slider-slide-wrap").each(function (i) {
var posLeft = $(this).position().left
var w = $(this).width();
// add shown class on a div
if (scrollLeft >= posLeft && scrollLeft < posLeft + w) {
$(this).addClass('shown').siblings().removeClass('shown');
}
// if .shown has .play-video, trigger play
if ($('.shown').is(".play-video")) {
$('video').trigger('play');
};
});

on scroll "sticky-element" will need stick to before "footer-area" not on bottom of page

I have one "sticky-element" div, on page load which I have been set position:fixed with bottom right aligned.
Requirement : on page scroll I would like to set it stick to just before on my "footer-area".
Issue : I have handled successfully css and js part on load, but I am not able to find logic that how can i add another class to my "sticky-element" once "footer-area" will start visible on window.
HTML
<div class="container">
<div class="page-section">
<p>lots of code and other div nested in this as well</p>
</div>
<div class="sticky-element">
</div>
<div class="footer-area">
</div>
</div>
jquery
$(window).on("load",function(){
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if(){
$(".sticky-element").addClass("some-class");
}
else {
$(".sticky-element").removeClass("some-class");
}
});
});
css
.sticky-element { position:fixed; }
.sticky-element.some-class { position:static; }
In above one if() my logic is that I would like to use if "footer-area" is visible on window than only add class will works.
Please suggest if anyone has Simple and short(not too much complex) coding way for this.
Thanks in advance
Try something like that:
<div class="container">
<div id='wraper'>
<div class="page-section">
<p>lots of code and other div nested in this as well</p>
</div>
<div class="sticky-element">
</div>
</div>
<div class="footer-area">
</div>
</div>
$(window).on("load",function(){
$(window).scroll(function() {
var bottomOfWraper = $('#wraper').offset().top + $('#wraper').outerHeight();
var bottomOfWin = $(window).scrollTop() + $(window).height();
if( bottomOfWin > bottomOfWraper){
$(".sticky-element").addClass("some-class");
}
else {
$(".sticky-element").removeClass("some-class");
}
});
});

Identify if child div reached top and bottom of parent

I've got a div inside another. The inner div (#items) scrolls within the parent div (#itemWrapper). I've got 2 arrows at the top an bottom.
I'm looking to hide the bottom arrow when the inner div reaches the bottom of the parent div and to hide the top arrow when the inner div reaches the top of its parent div.
My question is how do I get the distance / offset of the child div relative to its parent element to identify if it has reached the top or bottom?
Here is a FIddle
I tried this to find the position of the child div to its parent. But did not work.
EDIT:
html:
<div class="id="Wrapper">
<div class="row">
<img src="http://img42.com/p2OH4+" class="arrows" id="upArrow" height="128" width="128" />
<div id="itemWrapper">
<div id="items">
<div class="content">
<input type="image" src="http://img42.com/p1puE+" class = "thumb" />
</div>
<div class="content">
<input type="image" src="http://img42.com/p1puE+" class = "thumb" />
</div>
<div class="content">
<input type="image" src="http://img42.com/p1puE+" class = "thumb" />
</div>
</div>
</div>
<img src="http://img42.com/h1DoP+" class="arrows" id="downArrow" height="128" width="128" />
</div>
</div>
jQ:
('#subGrHolder').offset().top - $('#subGrHolder').parent().offset().top - $('#subGrHolder').parent().scrollTop();
I am going to put here what I said in comments in detail. Hope this is what you were looking for.
JavaScript:
var items = $('#items');
var upArrow = $('#upArrow');
var downArrow = $('#downArrow');
var scrollFactor = 100;
var scrollLeeway = 2;
items.on('scroll', onScroll);
upArrow.on('click', onUp);
downArrow.on('click', onDown);
function onScroll() {
if (items.scrollTop() === 0) {
upArrow.css('opacity', 0.1);
} else if (items[0].scrollHeight - items.scrollTop() <= items.height() + scrollLeeway) {
downArrow.css('opacity', 0.1);
} else {
upArrow.removeAttr('style');
downArrow.removeAttr('style');
}
}
function onUp(){ items.scrollTop(items.scrollTop() - scrollFactor); }
function onDown(){ items.scrollTop(items.scrollTop() + scrollFactor); }
jsFiddle.
Apologies if I have misunderstood your question entirely.

Categories