bootstrap源码之滚动监听组件scrollspy.js详解
其實滾動監(jiān)聽使用的情況還是很多的,比如導(dǎo)航居于右側(cè),當(dāng)主題內(nèi)容滾動某一塊的時候,右側(cè)導(dǎo)航對應(yīng)的要高亮。
實現(xiàn)功能
1、當(dāng)滾動區(qū)域內(nèi)設(shè)置的hashkey距離頂點到有效位置時,就關(guān)聯(lián)設(shè)置其導(dǎo)航上的指定項
2、導(dǎo)航必須是 .nav > li > a 結(jié)構(gòu),并且a上href或data-target要綁定hashkey
3、菜單上必須有.nav樣式
4、滾動區(qū)域的data-target與導(dǎo)航父級Id(一定是父級)要一致。
下面來看一下實現(xiàn)的具體代碼,原理:當(dāng)滾動容器內(nèi)的hashkey位置距離容器頂部只有 offset設(shè)置的值,就會設(shè)置導(dǎo)航中對應(yīng)的href高亮。
ScrollSpy構(gòu)造函數(shù)
首先新建一個構(gòu)造函數(shù),如下:
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 = nullthis.scrollHeight = 0this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))this.refresh()this.process()}該構(gòu)造函數(shù)主要干了啥:
1.基本設(shè)置,主要是設(shè)置當(dāng)前滾動元素是設(shè)置的body還是具體的某一塊元素;其次是導(dǎo)航的結(jié)構(gòu)要是.nav li > a的結(jié)構(gòu),也就是你的菜單中也要有.nav這個class。
2.監(jiān)聽元素滾動的時候,執(zhí)行process方法。
3.同時初始化的時候也執(zhí)行了refresh與process方法。
下面講解一下這幾個方法。
getScrolHeight方法
獲取滾動容器的內(nèi)容高度(包含被隱藏部分)
this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)refresh方法
刷新并存儲滾動容器內(nèi)各hashkey的值
ScrollSpy.prototype.refresh = function () {var that = thisvar offsetMethod = 'offset'var offsetBase = 0this.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])})}它主要實現(xiàn)了什么呢?
1.默認(rèn)用offset來獲取定位值,如果滾動區(qū)域不是window則用position來獲取
if (!$.isWindow(this.$scrollElement[0])) {offsetMethod = 'position'offsetBase = this.$scrollElement.scrollTop()}2.根據(jù)導(dǎo)航上的hashkey來遍歷獲取 滾動區(qū)域內(nèi)的hashkey對應(yīng)的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方法
滾動條事件觸發(fā)函數(shù),用于計算當(dāng)前需要高亮那個導(dǎo)航菜單
ScrollSpy.prototype.process = function () {var scrollTop = this.$scrollElement.scrollTop() this.options.offsetvar scrollHeight = this.getScrollHeight()var maxScroll = this.options.offset scrollHeight - this.$scrollElement.height()var offsets = this.offsetsvar targets = this.targetsvar activeTarget = this.activeTargetvar iif (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 = nullreturn 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.offset2.滾動容器可以滾動的最大高度:
var maxScroll = this.options.offset scrollHeight - this.$scrollElement.height()3.設(shè)置滾動元素邏輯,給當(dāng)前匹配元素添加高亮:
for (i = offsets.length; i--;) {activeTarget != targets[i]&& scrollTop >= offsets[i]&& (offsets[i 1] === undefined || scrollTop < offsets[i 1])&& this.activate(targets[i])}active方法
設(shè)置指定的導(dǎo)航菜單高亮
ScrollSpy.prototype.activate = function (target) {this.activeTarget = targetthis.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 = 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 = nullthis.scrollHeight = 0this.$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 = thisvar offsetMethod = 'offset'var offsetBase = 0this.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.offsetvar scrollHeight = this.getScrollHeight()var maxScroll = this.options.offset scrollHeight - this.$scrollElement.height()var offsets = this.offsetsvar targets = this.targetsvar activeTarget = this.activeTargetvar iif (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 = nullreturn 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 = targetthis.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')}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' && optionif (!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 = oldreturn 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);?
更多專業(yè)前端知識,請上 【猿2048】www.mk2048.com
總結(jié)
以上是生活随笔為你收集整理的bootstrap源码之滚动监听组件scrollspy.js详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS对全角与半角的验证,相互转化以及介绍
- 下一篇: swfobject.js视频播放插件