最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - click button scroll to specific div - Stack Overflow

programmeradmin2浏览0评论

I have a page that has a fixed menu and content box(div). When click the menu, content box scroll to specific div.

So far so good.

This is the sample here. /

The problem is when I wrap this whole div and, make them as show/hide toggle button, the scroll is not working.

This is the sample that not working. /

Also here is the snippet

$('.btn').click(function() {
  $(".wrap").toggleClass('on');
});
 
var div_parent_class_name;
var divs_class;
var id_offset_map = {};
$(document).ready(function() { 
    div_parent_class_name = "wrap_scroll";
    divs_class = "page-section"; 

    var scroll_divs = $("." + div_parent_class_name).children();
    id_offset_map.first = 0;
    scroll_divs.each(function(index) {
        id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
    });

    $('a').bind('click', function(e) {
        e.preventDefault();
        var target = $(this).attr("href")
        $('.wrap_scroll').stop().animate({
            scrollTop: id_offset_map[target]
        }, 600, function() {
            /* location.hash = target-20; */ //attach the hash (#jumptarget) to the pageurl
        });

        return false;
    });
});

$(".wrap_scroll").scroll(function() {
    var scrollPos = $(".wrap_scroll").scrollTop();
    $("." + divs_class).each(function(i) {
        var divs = $("." + divs_class);

        divs.each(function(idx) {
            if (scrollPos >= id_offset_map["#" + this.id]) {
                $('.menu>ul>li a.active').removeClass('active');
                $('.menu>ul>li a').eq(idx).addClass('active');
            }
            
        }); 
    });
}).scroll();
body,
html {
    margin: 0;
    padding: 0;
    height: 3000px;
}


.wrap { display:none;}
.wrap.on { display:block;}

.menu {
    width: 100px;
    position: fixed;
    top: 40px;
    left: 10px;
}

.menu a.active {
    background: red
}

.wrap_scroll {
    position: absolute;
    top: 20px;
    left: 150px;
    width: 500px;
    height: 500px;
    overflow-y: scroll
}

#home {
    background-color: #286090;
    height: 200px;
}

#portfolio {
    background: gray;
    height: 600px;
}

#about {
    background-color: blue;
    height: 800px;
}

#contact {
    background: yellow;
    height: 1000px;
}
<script src=".3.1/jquery.min.js"></script>
<button class="btn">show/hide</button> 

<div class="wrap">  
  <div class="menu">
      <ul>
          <li><a class="active" href="#home">Home</a> </li>
          <li><a href="#portfolio">Portfolio</a> </li>
          <li><a href="#about">About</a> </li>
          <li><a href="#contact">Contact</a> </li>
      </ul>a
  </div> 
  
  <div class="wrap_scroll">
      <div class="page-section" id="home">hh</div>
      <div class="page-section" id="portfolio">pp</div>
      <div class="page-section" id="about">aa</div>
      <div class="page-section" id="contact">cc</div>
  </div>

</div>

I have a page that has a fixed menu and content box(div). When click the menu, content box scroll to specific div.

So far so good.

This is the sample here. https://jsfiddle/ezrinn/8cdjsmb9/11/

The problem is when I wrap this whole div and, make them as show/hide toggle button, the scroll is not working.

This is the sample that not working. https://jsfiddle/ezrinn/8cdjsmb9/10/

Also here is the snippet

$('.btn').click(function() {
  $(".wrap").toggleClass('on');
});
 
var div_parent_class_name;
var divs_class;
var id_offset_map = {};
$(document).ready(function() { 
    div_parent_class_name = "wrap_scroll";
    divs_class = "page-section"; 

    var scroll_divs = $("." + div_parent_class_name).children();
    id_offset_map.first = 0;
    scroll_divs.each(function(index) {
        id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
    });

    $('a').bind('click', function(e) {
        e.preventDefault();
        var target = $(this).attr("href")
        $('.wrap_scroll').stop().animate({
            scrollTop: id_offset_map[target]
        }, 600, function() {
            /* location.hash = target-20; */ //attach the hash (#jumptarget) to the pageurl
        });

        return false;
    });
});

$(".wrap_scroll").scroll(function() {
    var scrollPos = $(".wrap_scroll").scrollTop();
    $("." + divs_class).each(function(i) {
        var divs = $("." + divs_class);

        divs.each(function(idx) {
            if (scrollPos >= id_offset_map["#" + this.id]) {
                $('.menu>ul>li a.active').removeClass('active');
                $('.menu>ul>li a').eq(idx).addClass('active');
            }
            
        }); 
    });
}).scroll();
body,
html {
    margin: 0;
    padding: 0;
    height: 3000px;
}


.wrap { display:none;}
.wrap.on { display:block;}

.menu {
    width: 100px;
    position: fixed;
    top: 40px;
    left: 10px;
}

.menu a.active {
    background: red
}

.wrap_scroll {
    position: absolute;
    top: 20px;
    left: 150px;
    width: 500px;
    height: 500px;
    overflow-y: scroll
}

#home {
    background-color: #286090;
    height: 200px;
}

#portfolio {
    background: gray;
    height: 600px;
}

#about {
    background-color: blue;
    height: 800px;
}

#contact {
    background: yellow;
    height: 1000px;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">show/hide</button> 

<div class="wrap">  
  <div class="menu">
      <ul>
          <li><a class="active" href="#home">Home</a> </li>
          <li><a href="#portfolio">Portfolio</a> </li>
          <li><a href="#about">About</a> </li>
          <li><a href="#contact">Contact</a> </li>
      </ul>a
  </div> 
  
  <div class="wrap_scroll">
      <div class="page-section" id="home">hh</div>
      <div class="page-section" id="portfolio">pp</div>
      <div class="page-section" id="about">aa</div>
      <div class="page-section" id="contact">cc</div>
  </div>

</div>

What Do I need to fix the code? please help.

Share Improve this question asked Mar 14, 2019 at 5:15 kk kkkk kk 3094 silver badges10 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 2

When you calculate your offset, the div is hidden with display: none. This results in the offsets being set/calculated to zero.

Here's a quick fix I threw together: https://jsfiddle/hrb58zae/

Basically, moved the logic to determine offset after clicking show/hide.

var setOffset = null;

...

if (!setOffset) {
    var scroll_divs = $("." + div_parent_class_name).children();
    id_offset_map.first = 0;
    scroll_divs.each(function(index) {
        id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
    });
    setOffset = true;
}

In your CSS, instead of using display: none and display: block, try using visible instead:

.wrap { visibility:hidden;}
.wrap.on { visibility:visible;}

This will hide the element without affecting the layout.

Updated fiddle: https://jsfiddle/a5u683es/

The problem was you are trying to update id_offset_map when content was hidden. When you use 'display:none' prop you won't get dimensions for that element and so its not working.

I updated the logic please check the fiddle https://jsfiddle/qfrsmnh5/

var id_offset_map = {};
var div_parent_class_name = "wrap_scroll";
var divs_class = "page-section"; 
var scroll_divs = $("." + div_parent_class_name).children();
   
function updateOffsets(){
    id_offset_map.first = 0;
    scroll_divs.each(function(index) {
        id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
    });

}

$(document).ready(function() { 

    $('.btn').click(function() {
      $(".wrap").toggleClass('on');
      if($(".wrap").hasClass("on")){
        updateOffsets();
      }
    });

    $('a').on('click', function(e) {
        e.preventDefault();
        var target = $(this).attr("href")
        $('.wrap_scroll').stop().animate({
            scrollTop: id_offset_map[target]
        }, 600, function() {
            /* location.hash = target-20; */ //attach the hash (#jumptarget) to the pageurl
        });

        return false;
    });
});

$(".wrap_scroll").on('scroll',function() {
    var scrollPos = $(".wrap_scroll").scrollTop();
    $("." + divs_class).each(function(i) {
        var divs = $("." + divs_class);

        divs.each(function(idx) {
            if (scrollPos >= id_offset_map["#" + this.id]) {
                $('.menu>ul>li a.active').removeClass('active');
                $('.menu>ul>li a').eq(idx).addClass('active');
            }
            
        }); 
    });
}).scroll();
body,
html {
    margin: 0;
    padding: 0;
    height: 3000px;
}


.wrap { display:none;}
.wrap.on { display:block;}

.menu {
    width: 100px;
    position: fixed;
    top: 40px;
    left: 10px;
}

.menu a.active {
    background: red;
}

.wrap_scroll {
    position: absolute;
    top: 20px;
    left: 150px;
    width: 500px;
    height: 500px;
    overflow-y: scroll;
}

#home {
    background-color: #286090;
    height: 200px;
}

#portfolio {
    background: gray;
    height: 600px;
}

#about {
    background-color: blue;
    height: 800px;
}

#contact {
    background: yellow;
    height: 1000px;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">show/hide</button> 

<div class="wrap">  
  <div class="menu">
      <ul>
          <li><a class="active" href="#home">Home</a></li>
          <li><a href="#portfolio">Portfolio</a> </li>
          <li><a href="#about">About</a> </li>
          <li><a href="#contact">Contact</a> </li>
      </ul>
  </div> 
  
  <div class="wrap_scroll">
      <div class="page-section" id="home">hh</div>
      <div class="page-section" id="portfolio">pp</div>
      <div class="page-section" id="about">aa</div>
      <div class="page-section" id="contact">cc</div>
  </div>

</div>

works perfectly, it's just that when you use display: none you can not do the offsetTop calculations because in fact the element is not rendered, I'm not sure if all the values ​​give 0 or undefined, I guess undefined, a solution is always calculate Positions using a function:

var div_parent_class_name;
var divs_class;
var id_offset_map = {};
function calcTops(){
    div_parent_class_name = "wrap_scroll";
    divs_class = "page-section"; 
    var scroll_divs = $("." + div_parent_class_name).children();
    id_offset_map.first = 0;
    scroll_divs.each(function(index) {
        id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
    });
}

https://jsfiddle/561oe7rb/1/

is not the optimal way, but it is to give you an idea. Sorry for my English.

Just Checkout This Working page I have designed

jQuery(document).on('scroll', function(){
			onScroll();

		});
		jQuery(document).ready(function($) {
			div_slider();
			showhide();
		});

		/*show hide content*/
		function showhide(){
			$('.toggle-wrapper button').on('click', function(){
				$('.wrapper').toggle();
				// div_slider();
			})
		}	

		/*scrolling page on header elements click*/
		function div_slider(){
			$('ul li a').on('click', function(e){
				e.preventDefault();
				$('ul li a').removeClass('active');
				$(this).addClass('active');
				var attrval = $(this.getAttribute('href'));
				$('html,body').stop().animate({
					scrollTop: attrval.offset().top
				}, 1000)
			});
		}

		/*adding active class on header elements on page scroll*/
		function onScroll(event){
			var scrollPosition = $(document).scrollTop();
			$('ul li a').each(function () {
				var scroll_link = $(this);
				var ref_scroll_Link = $(scroll_link.attr("href"));
				if (ref_scroll_Link.position().top <= scrollPosition && ref_scroll_Link.position().top + ref_scroll_Link.height() > scrollPosition) {
					$('ul li a').removeClass("active");
					scroll_link.addClass("active");
				}
				else{
					scroll_link.removeClass("active");
				}
			});
		}
body {
	margin: 0;
}
.toggle-wrapper {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	background-color: #ccd2cc;
	text-align: center;
}
.toggle-wrapper button {
	background-color: #ED4C67;
	color: #ffffff;
	padding: 10px 20px;
	border: 0;
	cursor: pointer;
	border-radius: 5px;
}
.toggle-wrapper button:active{
	background-color: #B53471;
}
header {
	background-color: #6C5CE7;
	position: fixed;
	top: 36px;
	z-index: 99;
	left: 0;
	right: 0;
}
	header ul {
	list-style: none;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 0;
	margin: 0;
}
ul li {
	flex: 1 100%;
	display: flex;
	justify-content: center;
}
.wrapper {
	margin-top: 36px;
}
header a {
	color: #ffffff;
	padding: 15px;
	display: block;
	text-decoration: navajowhite;
	text-transform: uppercase;
	width: 100%;
	text-align: center;
}
header a.active {
	color: #000000;
	background-color: #ffffff;
}
section {
	height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
}
section.section1 {
	background-color: #FFEAA7;
}
section.section2{
	background-color:#FAB1A0;
}
section.section3{
	background-color:#7F8C8D;
}
section.section4{
	background-color:#4CD137;
}
section.section5{
	background-color:#A3CB38;
}
section.section6{
	background-color:#70A1FF;
}
section.section7{
	background-color:#079992;
}
<div class="toggle-wrapper">
		<button>Toggle</button>
	</div>
	<div class="wrapper" style="display: none;">
		<header>
			<ul>
				<li><a class="active" href="#one">one</a></li>
				<li><a href="#two">two</a></li>
				<li><a href="#three">three</a></li>
				<li><a href="#four">four</a></li>
				<li><a href="#five">five</a></li>
				<li><a href="#six">six</a></li>
				<li><a href="#seven">seven</a></li>
			</ul>
		</header>
		<section class="section1" id="one">SECTION ONE</section>
		<section class="section2" id="two">SECTION TWO</section>
		<section class="section3" id="three">SECTION THREE</section>
		<section class="section4" id="four">SECTION FOUR</section>
		<section class="section5" id="five">SECTION FIVE</section>
		<section class="section6" id="six">SECTION SIX</section>
		<section class="section7" id="seven">SECTION SEVEN</section>
	</div>
  <script src="https://ajax.googleapis./ajax/libs/jquery/3.3.1/jquery.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论