JavaScript

超轻量级php框架startmvc

Bootstrap滚动监听组件scrollspy.js使用方法详解

更新时间:2020-05-25 18:00:01 作者:startmvc
其实滚动监听使用的情况还是很多的,比如导航居于右侧,当主题内容滚动某一块的时候,

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

实现功能

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> </li> 
<li><a href="#two">two</a> </li> 
<li><a href="#three">three</a> </li> 
</ul>
</div>
<div data-spy="scroll" data-target="#selector" style="height:100px; overflow:hidden;overflow-y: auto;" > 
<h4 id="one" >ibe</h4><p>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/></p> 
<h4 id="two" >two</h4><p>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/></p> 
<h4 id="three" >three</h4><p>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/>One的具体内容<br/></p>
</div>

下面来看一下实现的具体代码,原理:当滚动容器内的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))
 this.refresh()
 this.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 = function () {
 var that = this
 var offsetMethod = 'offset'
 var offsetBase = 0

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

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

 this.$body
 .find(this.selector)
 .map(function () {
 var $el = $(this)
 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(function () {
 that.offsets.push(this[0])
 that.targets.push(this[1])
 })

 }

它主要实现了什么呢?

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


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

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


this.$body
 .find(this.selector)
 .map(function () {
 var $el = $(this)
 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(function () {
 that.offsets.push(this[0])
 that.targets.push(this[1])
 })

process方法

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


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

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

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

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

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

主要作用:

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


var scrollTop = this.$scrollElement.scrollTop() + this.options.offset

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


var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()

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


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

active方法

设置指定的导航菜单高亮


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

 this.clear()

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

 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 = function () {
 $(this.selector)
 .parentsUntil(this.options.target, '.active')
 .removeClass('active')
 }

 源码


+function ($) {
 'use strict';

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

 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))
 this.refresh()
 this.process()
 }

 ScrollSpy.VERSION = '3.3.7'

 ScrollSpy.DEFAULTS = {
 offset: 10
 }

 ScrollSpy.prototype.getScrollHeight = function () {
 return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
 }

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

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

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

 this.$body
 .find(this.selector)
 .map(function () {
 var $el = $(this)
 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(function () {
 that.offsets.push(this[0])
 that.targets.push(this[1])
 })

 }

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

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

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

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

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

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

 this.clear()

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

 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')
 }

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


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

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

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

 var old = $.fn.scrollspy

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


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

 $.fn.scrollspy.noConflict = function () {
 $.fn.scrollspy = old
 return this
 }


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

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

}(jQuery);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

Bootstrap 滚动监听 scrollspy.js