Is there a way to instantly snap to the top of the page without scrolling, when pressing a button? I saw that there are a few ways to scroll to the top, but they are always kinda smooth-scroll.
Here's how to do it:
// the button is stored in the variable topScroll
// the first parameter in scrollTo is x axis and second is y
topScroll.onclick = () => window.scrollTo(window.scrollX, 0);
//If you don't want to manipulate scrollX
topScroll.onclick = () => window.scrollTo(window.scrollX, 0);
tell me if this works
document.addEventListener("DOMContentLoaded", function(){
// We get the Container Element, to prepend some random Elements to increase the Length.
const containerEl = document.getElementById('container')
// Loop to insert 100 paragraph elements with random Number
for(let i = 0; i < 100; i++){
const newEl = document.createElement('p');
newEl.innerText = Math.floor(Math.random()*1000000);
containerEl.prepend(newEl);
}
// We create a Header Element for the Top page
const titleEl = document.createElement("h1");
titleEl.innerText = "U.S.S Enterprise";
containerEl.prepend(titleEl);
// We jump to the bottom of the Page
const containerHeight = containerEl.offsetHeight;
window.scrollTo(0, containerHeight);
// We add a EventListener for the Button at the bottom of the Page
document.getElementById('scrollTopBtn').addEventListener("click", function(){
// When clicked, we jump to the top of the page
// The User can set a default Behavior for scrolling in the Browser as Accessability
// Setting. If you dont override it, it defaults to auto and using this browser set
// Setting. Therefore we define the behavior as instant.
window.scrollTo({
top: 0,
left: 0,
behavior: 'instant'
});
});
})
<div id="container">
<button id="scrollTopBtn">Beam me up, Scotty!</button>
</div>
Use this function when user click the button:
function scrollToTop(){
document.documentElement.scrollTop = 0;
}
Related
I have a list of chat messages inside a div and want to scroll to the bottom each time an element is added. I tried calling a function that selects the last item and uses scrollIntoView().
scrollToElement:function() {
const el = this.$el.getElementsByClassName('message');
if (el) {
el[el.length-1].scrollIntoView({behavior: "smooth"});
}
}
The issue is that it scrolls to the top of the selected element and not to the bottom of it which is needed in order to include the entire element into view.
I expected:
I got:
Every time you append a new chat message to the chat container - you need to scroll the chat container to its bottom edge. You can do that with a simple assignment:
this.$refs.chatContainer.scrollTop = this.$refs.chatContainer.scrollHeight;
Please note that the scrolling must be performed inside $nextTick to ensure that the new chat message has been added to the DOM.
My advice is to use a Vue directive on the chat container which will automatically scroll to the bottom every time a new chat message has been added:
function scrollToBottom(el)
{
el.scrollTop = el.scrollHeight;
}
// Monitors an element and scrolls to the bottom if a new child is added
// (always:false = prevent scrolling if user manually scrolled up)
// <div class="messages" v-chat-scroll="{always: false}">
// <div class="message" v-for="msg in messages">{{ msg }}</div>
// </div>
Vue.directive('chat-scroll',
{
bind: function(el, binding)
{
var timeout, scrolled = false;
el.addEventListener('scroll', function(e)
{
if (timeout) window.clearTimeout(timeout);
timeout = window.setTimeout(function()
{
scrolled = el.scrollTop + el.clientHeight + 1 < el.scrollHeight;
}, 200);
});
(new MutationObserver(function(e)
{
var config = binding.value || {};
var pause = config.always === false && scrolled;
if (pause || e[e.length - 1].addedNodes.length != 1) return;
scrollToBottom(el);
})).observe(el, {childList: true});
},
inserted: scrollToBottom
});
I'm trying to create a smooth scrolling effect using javascript library react. I don't want to use JQuery.
I want to archive when user clicks on a link that he goes to appropriate section of the page.
My handleScroll function is as follows :
handleScroll(ref, offsets, event){
event.preventDefault();
let offset = offsets[ref]; // this is where it needs to scroll for example 900
let activeLinks = {};
activeLinks[ref] = "active";
let start = new Date().getTime();
let time = 4000;
let offsetTo = this.state.offsetTo; //offsetTo is 0 on page load
let timer = setInterval(function() {
let step = Math.min(1,(new Date().getTime()-start)/time);
offsetTo = offsetTo + 40;
if(offsetTo >= offset) {
return;
}
window.scrollTo(0, offsetTo);
if( step == 1) clearInterval(timer);
},10);
this.setState({activeLinks: activeLinks}, () => timer);
}
This works pretty fine but only if I'm top of the page. When I click on the link it goes to the appropriate section with an animation.
But when I then click on some other link it works, but it starts from the top and not from the place where I am.
I need to find a way to set the offsetTo to the appropriate value, and then depending on it to go to the top or to the bottom.
Any idea how can I do that?
https://github.com/fisshy/react-scroll should do the trick.
see the examples, it's pretty straight forward.
I have a div called #menu which I want to display when I scroll past the element #section3, if I scroll up past that element again, I want #menu to disappear
How would I code this?
Maybe something like this?
scrolled = "no"
$(window).scroll(function(){
scr = $("body").scrollTop();
if (scr > 100 && scrolled == "no"){
$("#menu").css({"display:block"})
displayed = "yes"
}
if (displayed == "yes" && scrolled = "yes"){
$("#menu").css({"display:none"})
}
});
The above assumes that #section3 is 100 pixels down the page. If you do not know where its going to be on the page then you could use the method outlined here:
Trigger event when user scroll to specific element - with jQuery
With jQuery you can get the scroll position with $("body").scrollTop();.
Expanding on what #Ned Hulton said, I recommend comparing the scroll position to the top of a "container element" (or 'row') in your page like this:
if ($('body').scrollTop() > $('#someRow').offset().top){
//do something
}
That way you can account for your container appearing at a variable distance down the page (which will come in handy for mobile browsing or cases where your text wraps to additional lines)
I just whipped this up in jsfiddle
https://jsfiddle.net/rb56j0yu/
it uses jQuery, and checks the scroll position against the target div. Css sets the menu as position: fixed, and defaults to hidden.
$(window).scroll(function(){
var yPos = $("body").scrollTop();
var yCheck = $("#c3").position().top;
if (yPos > yCheck && !$("#menu").is(":visible"))
{
$("#menu").show();
}
if (yPos <= yCheck && $("#menu").is(":visible"))
{
$("#menu").hide();
}
});
First, get your #section3 top offset and height. Which will be used as the threshold whether #section3 is actually on the window screen.
var top = $('#section3').offset().top;
var bot = topOffset + $('#section3').height();
Then, detect it on your scroll event.
$(window).on('scroll', function () {
var scrollTop = $(window).scrollTop();
if (scrollTop >= top && scrollTop <= bot) {
// #section3 is within the screen.
$('#menu').show();
}
else {
// #section3 is out of screen.
$('#menu').hide();
}
});
This is a common use case, I wrote following code:
// what does "Auto Header" mean, goto https://www.yahoo.com/
// scroll down and you will see the purple part auto fixed to top,
// while when scroll up, it restores and does not be fixed.
// 1. multiple auto header elements handled
// 2. dynamically create/remove elements issue handled
// 3. no unnecessary dom operation, high performance
// usage: just add 'class="auto-header"' to any element you want to auto header
// suggest set each auto-header element specific width and height
// do not guarantee it works when resize or scroll left/right
$(document).ready(function() {
var rawTops = [],
rawLefts = [],
rawStyles = [],
$locations = [], // record next sibling so that element easily find where to restore
fixed = []; // mark whether this element is fixed
$(".auto-header").each(function() {
var $this = $(this),
offset = $this.offset();
rawTops.push(offset.top);
rawLefts.push(offset.left);
rawStyles.push($this.attr("style"));
$locations.push($this.siblings().eq($this.index()));
fixed.push(false);
});
$(window).on("scroll", function() {
$(".auto-header").each(function(i, e) {
if(!fixed[i] && $(window).scrollTop() > rawTops[i]) {
var $te = $(this).clone(true);
$(this).remove();
$locations[i].before($te);
$te.css({
"position": "fixed",
"top": 0,
"left": rawLefts[i],
"z-index": 100
});
fixed[i] = true;
} else if(fixed[i] && $(window).scrollTop() < rawTops[i]) {
$(this).removeAttr("style").attr("style", rawStyles[i]);
fixed[i] = false;
}
});
});
});
The general idea to the site i am designing is to scroll through a set of menu items horizontally and incrementally underneath a static div that will magnify(increase dimensions and pt size) the contents of a menu items. I don't really need help with the magnify portion because i think it's as simple as adding a mag class to any of the menuItem divs that go underneath the static div. I have been messing with this for a few weeks and the code I have for incrementally scrolling, so far, is this:
$(document).ready(function () {
currentScrollPos = $('#scrollableDiv').scrollTop(120); //sets default scroll pos
/*The incrementScroll function is passed arguments currentScrollPos and UserScroll which are variables that i have initiated earlier in the program, and then initiates a for loop.
-The first statement sets up the variables: nextScrollPos as equal to the currentScrollPos(which by default is 120px) plus 240px(the distance to next menuItem), prevScrollPos as equal to the currentScrollPos(which by default is 120px) minus 240px(the distance to next menuItem).
-The second Statement checks to see if the user has scrolled using var userScroll
-The third statement sets: var CurrentScroll equal to the new scroll position and var userScroll to false*/
function incrementScroll(currentScrollPos, userScroll) {
for (var nextScrollPos = parseInt(currentScrollPos + 240, 10),
prevScrollPos = parseInt(currentScrollPos - 240, 10); //end first statement
userScroll == 'true'; console.log('dude'), //end second statement and begining of third
currentScrollPos = scrollTop(), userScroll = 'false') {
if (scrollTop() < currentScrollPos) {
$('#scrollableDiv').animate({
scrollTop: (parseInt(prevScrollPos, 10))
}, 200);
console.log('scrolln up')
} else if (scrollTop() > currentScrollPos) {
$('#scrollableDiv').animate({
scrollTop: (parseInt(nextScrollPos, 10))
}, 200);
console.log('scrolln down')//fire when
}
}
}
$('#scrollableDiv').scroll(function () {
userScroll = 'true';
_.debounce(incrementScroll, 200); //controls the amount of times the incrementScroll function is called
console.log('straight scrolln')
});
});
I have found a variety of solutions that are nigh close: such as a plugin that snaps to the next or previous div horizontally demo, another solution that also snaps and is based on setTimeout demo, but nothing that nails incrementally scrolling through divs. I also found a way to control the rate at which a user may scroll through the menuItems using debounce which is included in the above code.
The console.logs inside the loop do not fire when I demo the code in jsfiddle which leads me to believe the problem lies within the loop. I'm a noob though so it could be in syntax or anywhere else in the code for that matter. Also in the second demo, i have provided the css for the horizontal static div, but the moment I put it in my html it keeps the js from working.
I would like to write the code instead of using a plugin and any help would be appreciated! Also, thank you ahead of time!
Try this fiddle. Menu container height is 960px to show 4 menu items. "Zoom" div is positioned absolutely at top. When you scroll mouse over this div, menu items shifts to top/bottom. I had to add additional div to bottom to be able to scroll to last 3 menu items. JS code:
jQuery(document).ready(function($){
var current = 0;
var menu = $('.menu-container').scrollTop(0);
var items = menu.find('.menu-item');
var zoom = $('.zoom');
function isVerticalScroll(event){
var e = event.originalEvent;
if (e.axis && e.axis === e.HORIZONTAL_AXIS)
return false;
if (e.wheelDeltaX)
return false;
return true;
}
function handleMouseScroll(event){
if(isVerticalScroll(event)){
var delta = event.originalEvent.wheelDelta * -1 || event.originalEvent.detail;
current += (delta > 0 ? 1 : -1);
if(current < 0)
current = 0;
if(current >= items.length){
current = items.length - 1;
}
menu.stop().animate({
"scrollTop": current * 240
}, 300);
items.removeClass('current').eq(current).addClass('current');
event && event.preventDefault();
return false;
}
}
zoom.on({
"MozMousePixelScroll": handleMouseScroll,
"mousewheel": handleMouseScroll
});
});
Hope it will help.
Background
I am trying to create an infinite scrolling table inside a fixed position div. The problem is that all the solutions I come across use the window height and document scrollTop to calculate if the user has scrolled to the bottom of the screen.
Problem
I have tried to create a jQuery plugin that can calculate if a user has scrolled to the bottom of a fixed div with overflow: scroll; set.
My approach has been to create a wrapper div (the div with a fixed position and overflow: scroll) that wraps the table, I also place another div at the bottom of the table. I then try calculate if the wrapper.scrollTop() is greater than the bottom div position.top every time the wrapper is scrolled. I then load the new records and append them to the table body.
$.fn.isScrolledTo = function () {
var element = $(this);
var bottom = element.find('.bottom');
$(element).scroll(function () {
if (element.scrollTop() >= bottom.position().top) {
var tableBody = element.find("tbody");
tableBody.append(tableBody.html());
}
});
};
$('.fixed').isScrolledTo();
See Example http://jsfiddle.net/leviputna/v4q3a/
Question
Clearly my current example is not correct. My question is how to I detect when a user has scrolled to the bottom of a fixed div with overflow:scroll set?
Using the bottom element is a bit clunky, I think. Instead, why not use the scrollHeight and height to test once the scrollable area has run out.
$.fn.isScrolledTo = function () {
var element = this,
tableBody = this.find("tbody");
element.scroll(function(){
if( element.scrollTop() >= element[0].scrollHeight-element.height()){
tableBody.append(tableBody.html());
}
});
};
$('.fixed').isScrolledTo();
EDIT (12/30/14):
A DRYer version of the plugin might be much more re-usable:
$.fn.whenScrolledToBottom = function (cback_fxn) {
this.on('scroll',this,function(){
if( ev.data.scrollTop() >= ev.data[0].scrollHeight - ev.data.height()){
return cback_fxn.apply(ev.data, arguments)
}
});
};
Plugin Usage:
var $fixed = $('.fixed'),
$tableBody = $fixed.find("tbody");
$fixed.whenScrolledToBottom(function(){
// Load more data..
$tableBody.append($tableBody.html());
});
I have modified your code to handle the scroll event with a timer threshold:
$.fn.isScrolledTo = function () {
var element = $(this);
var bottom = element.find('.bottom');
$(element).scroll(function(){
if (this.timer) clearTimeout(this.timer);
this.timer=setTimeout(function(){
if( element.scrollTop() >= bottom.position().top){
var tableBody = element.find("tbody");
tableBody.append(tableBody.html());
}
},300);
});
};
$('.fixed').isScrolledTo();
The issue you are having is that as you scroll, new scroll event is being generated. Your code might have other issues, but this is a start.