bootstrap源码之滚动监听组件scrollspy.js详解

其实滚动监听使用的情况还是很多的,比如导航居于右侧,当主题内容滚动某一块的时候,右侧导航对应的要高亮。

实现功能

1、当滚动区域内设置的hashkey距离顶点到有效位置时,就关联设置其导航上的指定项
2、导航必须是 .nav > li > a 结构,并且a上href或data-target要绑定hashkey
3、菜单上必须有.nav样式
4、滚动区域的data-target与导航父级Id(一定是父级)要一致。

<div id="selector" class="navbar navbar-default">  
ul class="nav navbar-nav"li><a href="#one">one</a> ="#two">two="#three">threeul>
divdata-spy="scroll" data-target="#selector" style="height:100px; overflow:hidden;overflow-y: auto;" h4 ="one" >ibeh4p>One的具体内容br/>One的具体内容/></="two" ="three" >

下面来看一下实现的具体代码,原理:当滚动容器内的hashkey位置距离容器顶部只有 offset设置的值,就会设置导航中对应的href高亮。

ScrollSpy构造函数

首先新建一个构造函数,如下:

function ScrollSpy(element,options) {
    this.$body          = $(document.body)
    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
    this.options        = $.extend({},ScrollSpy.DEFAULTS,options)
    this.selector       = (this.options.target || '') + ' .nav li > a'
    this.offsets        = []
    this.targets        =this.activeTarget   = null
    this.scrollHeight   = 0
    this.$scrollElement.on('scroll.bs.scrollspy',$.proxy(this.process,this))
    .refresh()
    .process()
  }

该构造函数主要干了啥:

1.基本设置,主要是设置当前滚动元素是设置的body还是具体的某一块元素;其次是导航的结构要是.nav li > a的结构,也就是你的菜单中也要有.nav这个class。

2.监听元素滚动的时候,执行process方法。

3.同时初始化的时候也执行了refresh与process方法。

下面讲解一下这几个方法。

getScrolHeight方法

获取滚动容器的内容高度(包含被隐藏部分)

this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)

refresh方法

刷新并存储滚动容器内各hashkey的值

ScrollSpy.prototype.refresh =  () {
    var that          = this
    var offsetMethod  = 'offset'
    var offsetBase    = 0

    this.offsets      =this.targets      =this.scrollHeight = .getScrollHeight()

    if (!$.isWindow(this.$scrollElement[0])) {
      offsetMethod = 'position'
      offsetBase   = .$scrollElement.scrollTop()
    }

    .$body
      .find(.selector)
      .map( () {
        var $el   = $()
        var href  = $el.data('target') || $el.attr('href'var $href = /^#./.test(href) && $(href)
        
        return ($href
          && $href.length
          && $href.is(':visible')
          && [[$href[offsetMethod]().top + offsetBase,href]]) || null
      })
      .sort(function (a,b) { return a[0] - b[0] })
      .each( () {
        that.offsets.push(this[0])
        that.targets.push(this[1])
      })

  }

它主要实现了什么呢?

1.默认用offset来获取定位值,如果滚动区域不是window则用position来获取

.$scrollElement.scrollTop()
    }

2.根据导航上的hashkey来遍历获取 滚动区域内的hashkey对应的offset值:

])
      })

process方法

滚动条事件触发函数,用于计算当前需要高亮那个导航菜单

ScrollSpy.prototype.process = var scrollTop    = this.$scrollElement.scrollTop() + .options.offset
    var scrollHeight = .getScrollHeight()
    var maxScroll    = this.options.offset + scrollHeight - .$scrollElement.height()
    var offsets      = .offsets
    var targets      = .targets
    var activeTarget = .activeTarget
    var i

    if (this.scrollHeight != scrollHeight) {
      .refresh()
    }

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets[targets.length - 1]) && .activate(i)
    }

    if (activeTarget && scrollTop < offsets[0]) {
      this.activeTarget = null
      return .clear()
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
        && .activate(targets[i])
    }
  }

主要作用:

1.获取滚动容器已滚动距离:

this.options.offset

2.滚动容器可以滚动的最大高度:

this.$scrollElement.height()

3.设置滚动元素逻辑,给当前匹配元素添加高亮:

.activate(targets[i])
    }

active方法

设置指定的导航菜单高亮

ScrollSpy.prototype.activate =  (target) {
    this.activeTarget = target

    .clear()

    var selector = this.selector +
      '[data-target="' + target + '"],' +
      this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

clear方法

清除所有高亮菜单

ScrollSpy.prototype.clear =  () {
    $(.selector)
      .parentsUntil(this.options.target,'.active')
      .removeClass('active')
  }

 源码

+ ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
   ==========================

  .process()
  }

  ScrollSpy.VERSION  = '3.3.7'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.getScrollHeight = this.$body[0].scrollHeight,document.documentElement.scrollHeight)
  }

  ScrollSpy.prototype.refresh = ])
      })

  }

  ScrollSpy.prototype.process = .activate(targets[i])
    }
  }

  ScrollSpy.prototype.activate = )
  }

  ScrollSpy.prototype.clear = )
  }


   SCROLLSPY PLUGIN DEFINITION
   ===========================

   Plugin(option) {
    this.each( () {
      var $this   = $()
      var data    = $this.data('bs.scrollspy'var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy',(data = new ScrollSpy(,options)))
      typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy


   SCROLLSPY NO CONFLICT
   =====================

  $.fn.scrollspy.noConflict =  () {
    $.fn.scrollspy = old
    
  }


   SCROLLSPY DATA-API
   ==================

  $(window).on('load.bs.scrollspy.data-api',1)"> () {
    $('[data-spy="scroll"]').each(var $spy = $()
      Plugin.call($spy,$spy.data())
    })
  })

}(jQuery);

 

相关文章

前端工程师一般用的是Bootstrap的框架而不是样式,样式一般自...
起步导入:<linkrel="stylesheet"href="b...
(1)modal声明一个模态框(2)modal-dialog定义模态框尺寸(...
图片在Bootstrap版本3中,通过为图片添加 .img-responsive ...
<inputtype="text"class="form-controlda...
目录bootstrap-treeview使用小记零、写在前面的话一、功能说...