How to style focused and visited anchors when scrolling with CSS / jQuery

╄→尐↘猪︶ㄣ 提交于 2019-12-11 09:27:58

问题


I have a rather complex question I cant seem to answer myself.

On the top of my page I have a couple anchors that smooth-scroll down to an article:

I want to tell the visitors their location on the page by rotating the arrow. This arrow should point towards the article it is representing. In the next image you can see how I want to implement this. Here, the user has scrolled past anchor 1 (this is an article with dynamic height) and is now reading the anchor 2 article:

When the visitor is outside the article, but the anchor 3 article is still below the scrolled position, it should look like this:

This creates a couple of problems for me:

  1. Is it possible to write the jQuery script so the anchors could be added dynamically?
  2. How to add a rotation animation without adding an extra library? (I'm now using jquery.transit )

Current code: (got this from another post: jsfiddle.net/m2zQE)

 var topRange      = 200,  // measure from the top of the viewport to X pixels down
     edgeMargin    = 20,   // margin above the top or margin from the end of the page
     animationTime = 1200, // time in milliseconds
     contentTop = [];

$(document).ready(function(){ 

 // Stop animated scroll if the user does something
 $('html,body').bind('scroll mousedown DOMMouseScroll mousewheel keyup', function(e){
 if ( e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel' ){
  $('html,body').stop();
 }
})

 // Set up content an array of locations
 $('#navTopBar').find('a').each(function(){
  contentTop.push( $( $(this).attr('href') ).offset().top );
 })

 // Animate menu scroll to content
  $('#navTopBar').find('a').click(function(){
   var sel = this,
       newTop = Math.min( contentTop[ $('#navTopBar a').index( $(this) ) ], $(document).height() - $(window).height() ); // get content top or top position if at the document bottom
   $('html,body').stop().animate({ 'scrollTop' : newTop }, animationTime, function(){
    window.location.hash = $(sel).attr('href');
   });
   return false;
 })

 // rotate arrow
 $(window).scroll(function(){
  var winTop = $(window).scrollTop(),
      bodyHt = $(document).height(),
      vpHt = $(window).height() + edgeMargin;  // viewport height + margin
  $.each( contentTop, function(i,loc){
   if ( ( loc > winTop - edgeMargin && ( loc < winTop + topRange || ( winTop + vpHt ) >= bodyHt ) ) ){
    $('#navTopBar .anchor img')
     .removeClass('open')
     .eq(i).addClass('open');
   }
  })
 })

})

Thanks in advance!


回答1:


I thought that code looked familiar ;)

Try something like this (demo)

CSS

li.selected a:after { content :' \2192' }
li.above a:after { content :' \2191' }
li.below a:after { content :' \2193' }

Script

 var topRange = 200, // measure from the top of the viewport to X pixels down
     edgeMargin = 20, // margin above the top or margin from the end of the page
     animationTime = 1200, // time in milliseconds
     contentTop = [];

 $(document).ready(function () {
     var $menu = $('#sidemenu li'),
         updateArrows = function (sel) {
             var indx = $menu.filter('.selected').index();
             $menu
                 .filter(':lt(' + indx + ')').removeClass('below').addClass('above').end()
                 .filter(':gt(' + indx + ')').removeClass('above').addClass('below');
         };

     // Stop animated scroll if the user does something
     $('html,body').bind('scroll mousedown DOMMouseScroll mousewheel keyup', function (e) {
         if (e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel') {
             $('html,body').stop();
         }
     });

     // Set up content an array of locations
     $menu.find('a').each(function () {
         contentTop.push($($(this).attr('href')).offset().top);
     });

     // Animate menu scroll to content
     $menu.find('a').click(function () {
         var sel = this,
             newTop = Math.min(contentTop[$('#sidemenu a').index($(this))], $(document).height() - $(window).height()); // get content top or top position if at the document bottom
         $('html,body').stop().animate({
             'scrollTop': newTop
         }, animationTime, function () {
             window.location.hash = $(sel).attr('href');
             updateArrows();
         });
         return false;
     });

     // adjust side menu
     $(window).scroll(function () {
         var sel,
         winTop = $(window).scrollTop(),
             bodyHt = $(document).height(),
             vpHt = $(window).height() + edgeMargin; // viewport height + margin
         $.each(contentTop, function (i, loc) {
             if ((loc > winTop - edgeMargin && (loc < winTop + topRange || (winTop + vpHt) >= bodyHt))) {
                 $menu.removeClass('selected')
                     .eq(i).removeClass('above below').addClass('selected');
             } else {
                 updateArrows();
             }
         });
     });

     updateArrows();

 });

In case you're interested, I actually turned that code into a plugin called visualNav; it doesn't include these changes - adding classes to links above & below the selected, but it should be relatively easy to add in the callback functions.



来源:https://stackoverflow.com/questions/25711004/how-to-style-focused-and-visited-anchors-when-scrolling-with-css-jquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!