I'm trying to avoid having the same lines of Javascript for the same purpose.
I have 3 sections:
<div class="specs"></div>
<div class="description"></div>
<div class="comments"></div>
And these 3 links:
Produkt beskrivelse
Produkt specs
</i>Kommentarer
And this javascript which, on click scrolls to the section
$(".facebook").on('click', function () {
$('html, body').animate({
scrollTop: $(".comments").offset().top - 200
}, 1000);
});
$(".readMore.desc").on('click', function () {
$('html, body').animate({
scrollTop: $(".description").offset().top - 200
}, 1000);
});
$(".readMore.spec").on('click', function () {
$('html, body').animate({
scrollTop: $(".specs").offset().top - 200
}, 1000);
});
These 3 pieces of javascript code is annoying because it does the exact same thing.
A live example can be seen here a live example. You'll see the 3 buttons on the right of the product image.
I don't know if a solution could be to add an array of some sort?
One way of handling this is giving each link a data- property that describes where the link should scroll to. You can use .data() to access these properties.
$(".readMore").on('click', function() {
// Get the selector of where to scroll to
var selector = $(this).data('selector');
$('html, body').animate({
scrollTop: $(selector).offset().top - 200
}, 1000);
});
html, body {
height: 100%;
}
div {
height: 100%;
margin-top: 20px;
border: solid 1px #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Produkt beskrivelse
Produkt specs
Kommentarer
<div class="specs">
Specs
</div>
<div class="description">
Description
</div>
<div class="comments">
Comments
</div>
Common classes (which you have) and data attributes will save you here.
Produkt beskrivelse
Produkt specs
</i>Kommentarer
And now, one handler to rule them all:
$(".readMore").on('click', function () {
var dest = $(this).data("dest");
$('html, body').animate({
scrollTop: $(dest).offset().top - 200
}, 1000);
});
//extraced the common parts
function scrollToTop ( elementSelector ) {
$('html, body').animate({
scrollTop: $(elementSelector).offset().top - 200
}, 1000);
}
$(".facebook").on('click', function () {
scrollToTop('.comments');
});
$(".readMore.desc").on('click', function () {
scrollToTop('.description');
});
$(".readMore.spec").on('click', function () {
scrollToTop('.specs');
});
Use a helper function instead of copy-pasting your code
function foo(target, element) {
target.on('click', function () {
$('html, body').animate({
scrollTop: element.offset().top - 200
}, 1000);
});
}
foo($(".facebook"), $(".comments"));
foo($(".readMore.desc"), $(".description"));
foo($(".readMore.spec"), $(".specs"));
Probably better you just read the class on the object, split it to get the value you want. As such:
$('.readMore').on('click', function() {
var classes = $(this).attr('class');
var cursor = class.split(' ')[1];
if(cursor == 'facebook') {
...
}else if(cursor == 'desc') {
...
} else if(cursor == 'spec') {
...
}
});
First you'll need to map which dom is effecting which. you could have solved this by using some kind of class name convention. I'll assume you can't decide on the class names. So let's create a map/object/hash
var map = {
spec: "specs",
desc: "description",
facebook: "comments,
}
Now let's just iterate the map and add the functionality
Object.keys(map).forEach(function(key) {
var value = map[key];
$(".readMore." + key).on('click', function () {
$('html, body').animate({
scrollTop: $("." + value).offset().top - 200
}, 1000);
});
})
And now you are a happy coder.
If you've learned closures, I prefer those to make re-usable events more readable...
I have a jsFiddle for this here
// use a closure to make your event's callback,
// with the target as a parameter
function makeClickFn(target) {
return function() {
$('html, body').animate({
scrollTop: $(target).offset().top - 200
}, 1000);
};
}
var clickFn;
// facebook comments
clickFn = makeClickFn('.comments');
$(".facebook").on('click', clickFn);
// readmore description
clickFn = makeClickFn('.description');
$(".readMore.desc").on('click', clickFn);
// readmore specs
clickFn = makeClickFn('.specs');
$(".readMore.spec").on('click', clickFn);
Related
I am trying to smooth scroll to a div after about a minute on a page. I looked on here and found this answer but it did not help me as the person who gave the answer didn't really answer the person's question.
I'd prefer to use jQuery but I am open to JavaScript as well.
Here is what I have so far:
$(document).ready(function() {
$('body').delay(5000)
.animate({
'scrollTop': $('#usp').offset().top
}, 5000);
});
You can use Something like this which is quite easy.
Just Create a function with some name and call it after few seconds.
$(document).ready(function() {
function scrolltodiv(){
$('html, body').animate({
scrollTop: $("#myDiv").offset().top
}, 2000);
}
window.setTimeout( scrolltodiv, 5000 );
});
I hope this helps:
( function($){
setTimeout( function() {
$('html, body').animate({
scrollTop: $("#elementID").offset().top
// you can use $(".elementClass") but as ID should be unique, it would be better to use an element ID instead of classes
}, 2000);
// 2000 ms is the animation duration
}, 5000)
// it scrolls to #elementID after 5000 ms = 5 secs
} )(jQuery);
$(function(){
setTimeout(function(){
animate("#idorclass" ,2000)
}, 5000)
})
const animate = (idorclass, animval)=>{
$('html, body').animate({
scrollTop: $(idorclass).offset().top
}, animval);
}
also dynamic function that you can reuse
I have an application with a landing page that has many sections, and use Scrollspy for the smooth scrolling effect in the page. At the end of my navigation items I have a call to action button that takes the user to another page. However, because it's in my navigation items, when the page loads, Scrollspy is throwing an error on the link to another page.
Uncaught Error: Syntax error, unrecognized expression: https://example.com/page2
Is there anything I can do to tell scrollspy to ignore that link or is there some other way to get rid of that error? Thanks!
Here is the code I am using to initialize scrollspy:
(function ($) {
'use strict';
// SmoothLink
function initSmoothLink() {
$('.nav-item a').on('click', function(event) {
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top - 0
}, 1500, 'easeInOutExpo');
event.preventDefault();
});
}
// StickyMenu
function initStickyMenu() {
$(window).on('scroll',function() {
var scroll = $(window).scrollTop();
if (scroll >= 50) {
$(".sticky").addClass("stickyadd");
} else {
$(".sticky").removeClass("stickyadd");
}
});
}
// Scrollspy
function initScrollspy() {
$("#navbarCollapse").scrollspy({
offset: 70
});
}
//MFPVideo
function initMFPVideo() {
$('.video_play').magnificPopup({
disableOn: 700,
type: 'iframe',
mainClass: 'mfp-fade',
removalDelay: 160,
preloader: false,
fixedContentPos: false
});
}
// Back To Top
function initBackToTop() {
$(window).on('scroll',function(){
if ($(this).scrollTop() > 100) {
$('.back_top').fadeIn();
} else {
$('.back_top').fadeOut();
}
});
$('.back_top, .footer_logo_link').on('click',function(){
$("html, body").animate({ scrollTop: 0 }, 1000);
return false;
});
}
function init() {
initSmoothLink();
initStickyMenu();
initScrollspy();
initMFPVideo();
initBackToTop();
}
$(document).on('turbolinks:load', function(){
init();
});
})(jQuery);
You can add in if statement to check if the href has a hash. If it doesn't have one, then it will just proceed as normal.
function initSmoothLink() {
$('.nav-item a').on('click', function(event) {
var $anchor = $(this);
if (this.hash !== "") {
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top - 0
}, 1500, 'easeInOutExpo');
event.preventDefault();
}
});
}
Scrollspy looks for all a tags in given container, takes href attribute and uses it's value as jQuery selector. Here is the possible solution using JS:
Page 2
Setting href and id is required in your case if you don't want to add additional checks in initSmoothLink() function.
I have the following jquery function which shows / hides content depending on the div that is selected...
jQuery(document).ready(function() {
jQuery('.showSingle').on('click', function () {
jQuery(this).addClass('selected').siblings().removeClass('selected');
jQuery('.targetDiv').hide();
var selector = '#div' + jQuery(this).data('target');
jQuery(selector).show();
location.hash = selector;
});
});
http://jsfiddle.net/W4Km8/7944/
I also have the following script taken from http://1stwebmagazine.com/jquery-scroll-to-anchor-point
$(document).ready(function(){
$('a[href^="#"]').bind('click.smoothscroll',function (e) {
e.preventDefault();
var target = this.hash,
$target = $(target);
$('html, body').stop().animate({
'scrollTop': $target.offset().top-40
}, 900, 'swing', function () {
window.location.hash = target;
});
});
});
I am trying to combine the 2 so that instead of jumping to the anchor it scrolls to it. Do I need to combine them or can they be made to work separate?
Looks like you can combine them easily enough, I've made it work with this jsfiddle: http://jsfiddle.net/9soxbhpj/
var target = jQuery(selector);
target.show()
$('html, body').stop().animate({
'scrollTop': target.offset().top-40
}, 900, 'swing', function () {
window.location.hash = selector;
});
You can add the scroll action in the same click call.
See the js:
jQuery(document).ready(function() {
jQuery('.showSingle').on('click', function () {
var _el = jQuery(this),
_target = jQuery('#div' + _el.data('target')),
_targetDiv = jQuery('.targetDiv');
_el.addClass('selected').siblings().removeClass('selected');
_targetDiv.hide();
_target.show();
// Scroll to object
$('html, body').animate({
scrollTop: _target.offset().top
}, 800);
});
});
Here is a working example.
So I have the following code:
$("#btn1").click(function(event) {
event.preventDefault();
$('html, body').animate({
scrollTop: $("#div").offset().top
}, 2000);
$("#div").addClass("flash");
setTimeout( function(){
$("#div").removeClass("flash"), 1000;
}, 1000);
});
When I click on the button it will scroll down to the div and flash its color (flash class). But what if the div is at the bottom of the page? I need the ode above to be changed so that the scrollTop is executed first AND is finished and then execute the next piece of code (the addClass and the setTimeout function). I assume I need to add a delay? Or something that checks whether the function is complete and if so, start the next one?
I think what you're looking for is animation callback. It's the forth parameter to the .animate() method: http://api.jquery.com/animate/
So in your case it would look like this:
$("#btn1").click(function(event) {
event.preventDefault();
$('html, body').animate({
scrollTop: $("#div").offset().top
},
2000,
'swing',
function () {
$("#div").addClass("flash");
setTimeout( function(){
$("#div").removeClass("flash"), 1000;
}, 1000);
});
});
Btw. it's a good practice to cache a jQuery selectors for optimisation (jQuery won't be searching the DOM for the queried nodes, and running the its constructor function each time).
I also refactored this code a bit for readability and to separate the flashing functionality, so you can either use it conveniently in such callbacks (in which case the function will get the animated element as this object, or just run it directly, passing it any jQuery element (e.g. flash($('.anything')))
$("#btn1").click(function(event) {
event.preventDefault();
$div = $('#div');
$('html, body').animate({
scrollTop: $div.offset().top
}, 2000, 'swing', flashElement});
});
function flashElement(element) {
element = element || this;
element.addClass("flash");
setTimeout( function(){
element.removeClass("flash"), 1000;
}, 1000);
}
You just need a callback...
$("#btn1").click(function(event) {
event.preventDefault();
$('html, body').animate({
scrollTop: $("#div").offset().top
}, 2000, function(){
$("#div").addClass("flash");
setTimeout( function(){
$("#div").removeClass("flash"), 1000;
}, 1000);
});
});
I have this code below and the DEMO fiddle.
jQuery(document).ready(function () {
$(window).scroll(function () {
$('html, body').animate({
scrollTop: $('#content').offset().top
}, 1000);
});
});
I'm really confused why I can't scroll up? Anybody can explain to me why and please share some solutions you have.
Any help, is very appreciated.
Alright, this should do what you are asking for. I don't think it is very user friendly, but that is up to you.
Demo Fiddle
//this prevents the animate method from running multiple times.
var scrolling = false;
jQuery(document).ready(function () {
$(window).scroll(function () {
if ( $(window).scrollTop() <= 100 && scrolling === false) {
//set to true to prevent multiple scrolls
scrolling = true;
//run the animation
$('html, body').animate({
scrollTop: $('#content').offset().top
}, 1000, function() {
//when animation is complete, set scrolling to false
scrolling = false;
});
}
});
});
You can't scroll up because your code is wrapped in the scroll() function so it basically locks its position every time you try and scroll with either the mouses scroll wheel or arrow keys. If you amend to the following then it will position itself accordingly when the page first loads.
jQuery(document).ready(function () {
$('html, body').animate({
scrollTop: $('#content').offset().top
}, 1000);
});
Are you trying to have it animate when the link is clicked? If so you need to change your code:
jQuery(document).ready(function () {
$('a').click(function () {
$('html, body').animate({
scrollTop: $('#content').offset().top
}, 1000);
});
});
I would probably add a class or ID value to your link so you can target that one specific link. The code above would apply to all links on your page...although right now there is only the one.
<h1>Scroll to the Content</h1>
jQuery(document).ready(function () {
$('.scrollToContent').click(function () {
$('html, body').animate({
scrollTop: $('#content').offset().top
}, 1000);
});
});
I'm not sure if you will satisfied on this but i found something that can help a little on my problem.
jQuery(document).ready(function () {
$(this).bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta /120 < 1) {
$('html, body').delay(200).animate({
scrollTop: $('#content').offset().top
}, 1000);
}
});
});
DEMO
No need to add the jquery functionality to achieve the requirement that has been asked. Please remove the Jquery code and run the code snippet provided in the fiddle. It is behaving as per the requirement.