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> </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   '"]'
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   '"]'
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);

 


更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366083.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言 指针_C语言——指针

学习阶段&#xff1a;高中信竞、大学编程。前置知识&#xff1a;二进制与十六进制&#xff0c;C语言基础&#xff0c;数组。指针初学可能比较难理解&#xff0c;我这篇文章尽量用通俗易懂的方式来讲解。1. 指针概述为什么有指针这个东西&#xff1f;因为指针很贴近计算机内部的…

将jOOQ与Spring结合使用:配置

我遇到了由ORM引起的性能问题。 尽管我不得不承认大多数这些问题确实是由您造成的&#xff0c;但是我开始认为在只读操作中使用ORM是不值得的。 我开始寻找实现这些操作的替代方法。 这就是我遇到jOOQ的方式 &#xff0c;它指出&#xff1a; jOOQ从您的数据库生成Java代码&a…

FFT实现高精度乘法

你应该知道$FFT$是用来处理多项式乘法的吧。 那么高精度乘法和多项式乘法有什么关系呢&#xff1f; 观察这样一个$20$位高精度整数$11111111111111111111$ 我们可以把它处理成这样的形式&#xff1a;$\sum_{i0}^{19}1\times10^i$ 这样就变成了一个多项式了&#xff01; 直接上代…

oracle精确匹配时间,Oracle时间精确到时、分、秒处理方法

Oracle时间精确到时、分、秒处理方法一般数据库中时间的格式为DATE类型&#xff0c;而我们从页面中获取的时间往往为String类型&#xff0c;这个就需要类型的转换。一般我们会通过调用 Java.text.SimpleDateFormat JAVA类来对其进行转换。这个JAVA类中我们经常用到的方法有两个…

BZOJ 2141 排队(分块+树状数组)

题意 第一行为一个正整数n&#xff0c;表示小朋友的数量&#xff1b;第二行包含n个由空格分隔的正整数h1,h2,…,hn&#xff0c;依次表示初始队列中小朋友的身高&#xff1b;第三行为一个正整数m&#xff0c;表示交换操作的次数&#xff1b;以下m行每行包含两个正整数ai和bi&…

骆驼路线的主/从故障转移

一种实现主/从故障转移模式的方法是拥有一个应用程序实例的集群&#xff0c;其中一个实例&#xff08;主实例&#xff09;当前处于活动状态&#xff0c;而其他实例&#xff08;从属实例&#xff09;处于待机状态&#xff0c;随时可以在主实例发生故障时接管。 一些项目提供了开…

vant input框禁止调用手机键盘_【案例分享】适应网银等密码键盘的解决方案

在各种技术不断进步的大趋势下&#xff0c;对业务造成了极大影响&#xff0c;从大数据到云计算&#xff0c;再到人工智能&#xff0c;众多企业都开始步入技术改革&#xff0c;从而实现企业的创新。但与此同时&#xff0c;更多技术的引用&#xff0c;意味着更多的业务系统上线&a…

JS无法获取display为none的隐藏元素的宽度和高度的解决方案

在实际开发中会遇到确实需要获取隐藏元素的宽高&#xff0c;这儿所说的隐藏元素是display为none的元素。 可使用jQuery Actual Plugin插件来完成&#xff0c;其源码如下&#xff1a; ;( function ( $ ){$.fn.addBack $.fn.addBack || $.fn.andSelf;$.fn.extend({actual : fun…

删除kafka topic

1、因为项目原因&#xff0c;kakfa通道中经常造成数据阻塞&#xff0c;导致kafka通道中数据量过大&#xff0c;因此我需要将kakfa通道中数据清除&#xff08;个人项目原因&#xff0c;一直使用一个消费者&#xff0c;只要保证当前消费者不在消费之前很久的数据就可以。因数量过…

启动oracle数据库工具,Oracle数据库常用工具

SQL*Plus:SQL*Plus 是Oracle 数据库的一个基本工具&#xff0c;它允许用户使用SQL 命令交互式的访问数据库&#xff0c;也允许用户使用SQL*Plus 命令格式化输出参数。 通过SQL*Plus &#xff0c;可以完成数据库的启动和停止、创建和运行查询、更新数据、格式化输出数据报表、运…

可持久化并查集小结

https://www.zybuluo.com/ysner/note/1253722 定义 允许恢复历史状态的并查集。 建立 建\(Q\)棵主席树&#xff0c;每个主席树上维护当前状态并查集各个节点的父亲。 &#xff08;实际上就是并查集和主席树强行捆绑在一起&#xff09; 操作 每次操作前自动继承上次操作后的状态…

Java 获取linux根目录下的文件夹_Windows支持直接访问Linux子系统文件:你的下一台Linux何必是Linux...

2020年第一波薅当当网羊毛的机会&#xff0c;别错过&#xff01;晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI 微软&#xff0c;致力于做最好的Linux发行版。今天&#xff0c;安装Windows 10测试版本号19603的用户发现&#xff0c;系统里WSL (Windows中的Linux子系统…

HTML5效果:实现树叶飘落

实现如图所示的东西效果&#xff08;落叶下落&#xff09;&#xff1a; html代码&#xff1a; <!DOCTYPE html><html><head><title>HTML5树叶飘落动画</title><meta charset"utf-8"><meta name"viewport" content&…

Java 8 Friday Goodies:Lambda和XML

在Data Geekery &#xff0c;我们喜欢Java。 而且&#xff0c;由于我们真的很喜欢jOOQ的流畅的API和查询DSL &#xff0c;我们对Java 8将为我们的生态系统带来什么感到非常兴奋。 我们已经写了一些关于Java 8好东西的博客 &#xff0c;现在我们觉得是时候开始一个新的博客系列了…

洛谷2619/bzoj2654 Tree(凸优化+MST)

bzoj的数据是真的水。。 qwq 由于本人还有很多东西不是很理解 qwq 所以这里只写一个正确的做法。 首先&#xff0c;我们会发现&#xff0c;对于你选择白色边的数目&#xff0c;随着数目的上涨&#xff0c;斜率是单调升高的。 那么这时候我们就可以考虑凸优化&#xff0c;也就是…

oracle 创交表,创建交叉报表(oracle)_oracle

创建交叉报表create table t1(goodid number(10) not null,saledate date not null,salesum number(10));要求生成本年度每个月的产品销售状况表m1 m2 m3 ... m12g1g2...gn下面是生成报表的sqlSELECT goodid,SUM(decode(to_char(saledate,mm),01,salesum)) "01"…

cass方格网数据excel_讨论|CASS怎么计算回字型土方? 124

大家好,欢迎来到我的专栏。这是我原创的第124篇CASS应用技术干货文章。希望对你有所帮助&#xff0c;写文不易&#xff0c;请点赞哦!回字型土方工程&#xff0c;就是计算区域内部&#xff0c;有一个或多个不参加计算的区域&#xff0c;这种区域也就是常说的“扣岛”。常见的有基…

ATM购物车程序项目规范(更新到高级版)

ATM购物车程序&#xff08;高级版&#xff09; 之前的低级版本已经删除&#xff0c;现在的内容太多&#xff0c;没时间把内容上传&#xff0c;有时间我会把项目源码奉上&#xff01; 我已经把整个项目源码传到群文件里了&#xff0c;需要的可以加主页qq群号。同时群内也有免费的…

垃圾收集器准则和提示

这些是我需要调整GC时通常会看到的一些准则和技巧。 主要由以下两本书组成&#xff0c;而根据我的经验却很少&#xff1a; Java性能 JBoss AS 5性能调优 希望它们对那里的其他人有用&#xff01; 垃圾收集器 XX:AggressiveOpts将HotSpot内部布尔变量设置为true以启用其他性…

MD5加密处理

MD5 加密后的位数一般为两种&#xff0c;16 位与 32 位。16 位实际上是从 32 位字符串中&#xff0c;取中间的第 9 位到第 24 位的部分 using System; using System.Security.Cryptography; using System.Text;namespace _04MD5加密 {internal class Program{private static vo…