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
bootstrap源码之滚动监听组件scrollspy.js详解相关推荐
- Bootstrap 滚动监听插件Scrollspy 的事件
事件 Bootstrap滚动监听插件Scrollspy提供了一个事件 activate,每当一个新的导航项目被激活时,就会触发该事件,并自动为导航条的相应菜单项添加了一个 .active 类,让它高亮 ...
- Bootstrap 滚动监听插件Scrollspy 的选项
选项 Bootstrap滚动监听插件Scrollspy提供了一个选项 offset,用来调整滚动位置距顶部偏移的像素值,取值为数字,默认值为10.正值表示滚动条向上偏移,负值表示向下偏移. 所有的选项 ...
- 最新未来码支付1.2开源版 免签约即时到账支付源码 不用挂监听!!
介绍: 未来码支付1.2开源版 免签约即时到账支付源码 不用挂监听! 安装要求: PHP5.6+ mysql5.5+ Apache或者nginx都可以 安装说明: 上传到网站目录,删除core目录里面 ...
- Java监听mysql的binlog详解(mysql-binlog-connector)
Java监听mysql的binlog详解(mysql-binlog-connector) 1. 需求概述 2. 技术选型 3. 方案设计 3.环境准备 3.1 查看是否开启binlog 3.2 mys ...
- Oracle11g安装教程、配置实例、监听、客户端程序详解_Windows篇
Oracle11g安装教程.配置实例.监听.客户端程序详解_Windows篇 文章目录 Oracle11g安装教程.配置实例.监听.客户端程序详解_Windows篇 前言 一.数据库的安装前准备,前提 ...
- KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解
KBQA_多轮对话--模型源码解析(一)Pickle模块功能详解 pickle --- Python 对象序列化的基本功能 1.pickle基本概念 2.pickle 与 json 模块的比较 3.p ...
- 【SA8295P 源码分析】53 - mifs.build.tmpl 脚本详解:启动QNX procnto-smp-instr微内核、启动QNX串口终端shell、加载解析并执行ifs2_la.img
[SA8295P 源码分析]53 - mifs.build.tmpl 脚本详解:启动QNX procnto-smp-instr微内核.启动QNX串口终端shell.加载解析并执行ifs2_la.img ...
- java毕业设计——基于java+Winpcap的局域网监听软件设计与实现(毕业论文+程序源码)——局域网监听软件
基于java+Winpcap的局域网监听软件设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+Winpcap的局域网监听软件设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦 ...
- Bootstrap 滚动监听插件Scrollspy 的方法
方法 通过 JavaScript 调用滚动监控插件时,如果监听对象的DOM节点有增删元素的操作,则需要调用 .scrollspy('refresh') 方法来更新DOM. <script> ...
最新文章
- 安装您的Sbo Add-on插件
- 截取指定字符前_Excel应该怎么学--表格维护常用文本函数(截取、转换、连接)...
- 欢迎广大测试人员,加入微信群,了解自动化测试的框架,检查点,参数化。...
- 【今天下午活动】从 HelloWorld 到 AntDesign,Blazor 将 .NET 带到现代前端圈
- 数据库中的表还是一定要建索引
- android json字符串转成json对象_C++ 两行代码实现json与类对象互转
- 小米平板5或无缘MIUI 13:搭配骁龙870 预装MIUI 12.5系统
- 中国联通4G携号转网业务支撑的架构实践
- Vue中watch监听数据变化以及watch中各属性详解
- 用python导出pptx中每一页的标题
- 数据结构实验1.2:高精度计算PI值
- 基于Web的电子商务解决方案(1)(转)
- 手环、APP监测睡眠可靠吗?
- 【控制系统的微分方程】
- 京东、天猫等电商平台产品评价
- html+css 基础知识大总结
- 显卡的指标有哪些方面_纯干货!显卡购买重要参数:老司机勿入
- LeetCode 46.全排列
- 全文检索-ElasticSearch入门
- 管理铁律:高层唱白脸,中层扮黑脸
热门文章
- Java锤子剪刀布大家应该都会玩“锤子剪刀布”的游戏: 现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。
- 非cpu0启动linux,SD卡无法启动Linux的问题及解决
- fprintf函数的用法matlab_极力推荐这个Matlab教程
- oracle 查询过去一个星期的数据_过去一星期,最懂我的居然是一个表情包
- 算法复杂度分析(下):最好、最坏、平均、均摊等时间复杂度概述
- zoj 3640 概率dp
- 物理路径与虚拟路径 及Web Server
- MySQL最早版本源码_MySQL旧版本升级为新版本
- jquery select change事件_jQuery实现省市联动效果
- opencv中的矩阵拼接