vue实现吸顶、锚点和滚动高亮按钮效果


Posted in Javascript onOctober 21, 2019

因公司后台管理系统很多功能技术老旧,最近在用vue重构公司的后台管理系统,在做商品管理添加商品这一块,借鉴淘宝的添加商品的交互,需要实现一个简单的吸顶、锚点和滚动高亮按钮的效果。

需求

  1. 滚动页面到顶部,实现某元素固定到顶部效果
  2. 点击某个按钮,页面滚动到相应的位置
  3. 滚动页面,当到达某个位置时,高亮对应的相关按钮

元素吸顶实现方式

关于元素吸顶效果,通过查阅相关资料和相关测试,有三种方式(还有一种是jquery的方法,这里就不介绍了)

一、使用position:sticky

1. 什么是position:sticky?

粘性定位元素相当于position:relative和position:sticky的结合体,受限于父级元素,在不同的条件下呈现出不同的页面效果

2. 如何使用sticky?

sticky元素效果完全受限于父级元素,使用条件:

1.sticky元素的父元素的overflow只能设置为visible,否则会导致没有粘滞效果

2.sticky元素的父元素不能设置固定的高度,否则会导致没有粘滞效果

3.sticky满足条件变成fixed定位时,与标准fixed元素不一样,不会脱离文档流

4.sticky 定位的元素不能添加一个只包含自身的父元素,会导致没有粘滞效果

5.同一个父级元素中的sticky元素,如果定位值相等,则会重叠,如果属于不同父级元素中,则会挤掉之前的元素,形成依次占位的效果 具体实现效果如下:

.sticky-box{ 
 position: sticky; 
 position: -webkit-sticky;
 top: 60px; //可通过js动态设置
}

3.兼容性

通过查看can i use 可以看到相关的兼容性:

可以看出这个属性的兼容性不是那么好,如果项目需要兼容到ie11等的话,就不是那么适用了

二、使用offsetTop**

HTMLElement.offsetTop 为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。因此我们需要注意的是,在监听页面滚动的过程中,需要将定位父级元素的偏移量也计算在内,可以如下写法:

//获取当前元素的offsetTop
  getOffsetTop(obj) {
   let offsetTop = 0;
   while (obj != window.document.body && obj != null) {
    offsetTop += obj.offsetTop;
    obj = obj.offsetParent;
   }
   return offsetTop;
  }

通过在vue的mounted生命周期函数中添加监听事件滚动的事件:

mounted() {
  /**通过给变成固定定位的元素添加一个同等高度的父元素,防止该元素变成固定定位时,脱离文档流导致的页面抖动 */
  this.tabsHeight = this.$refs.elTabs.offsetHeight;
  window.addEventListener("scroll", this.handleScroll);
 },
 destroyed() {
  //离开该页面需要移除这个监听的事件
  window.removeEventListener("scroll", this.handleScroll);
 },
  methods: {
  /**滚动事件 */
  handleScroll() {
    //获取页面滚动条的高度
    let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    let offsetTop = this.getOffsetTop(this.$refs.elTabs);
    this.isFixed = scrollTop > offsetTop;
  }
 }

同时如果这种吸顶方式在项目中会多次用到,就可以封装成组件的形式

三、使用getBoundingClientRect().top**

还有一种更为直接的方式,可以实现吸顶效果,就是使用getBoundingClientRect().top来获取元素相对于视口(浏览器窗口)的位置,相对于offsetTop,该方法不用考虑到吸顶元素的父级元素和页面滚动条的高度,直接对该元素进行处理即可,实现如下: /* 滚动事件 / handleScroll() { / * getBoundingClientRect().top 获取某元素距离浏览器顶部的高度,不包含滚动的距离 */ let tabOffsetTop = this.$refs.stickyBox.getBoundingClientRect().top; this.isFixed = tabOffsetTop < this.offsetTop }

/**滚动事件 */
  handleScroll() {
   /**
    * getBoundingClientRect().top 获取某元素距离浏览器顶部的高度,不包含滚动的距离
    this.offsetTop 表示的是吸顶元素距离顶部的条件值(一般项目需求是0)
    */
   let tabOffsetTop = this.$refs.stickyBox.getBoundingClientRect().top;
   this.isFixed = tabOffsetTop < this.offsetTop
  }

锚点定位

点击相应的按钮,页面滚动到相应的位置,目前我知道实现该功能的方式有两种:

1. 使用a标签定位 2. 使用js模拟锚点定位

使用a标签定位

这是一种常见的定位方式,它有两种实现方式:

1. 通过href属性链接到指定元素的id

2.另一种是添加一个 a 标签,再将 href 属性链接到这个 a 标签的 name 属性

<a href="#view1">按钮1</a> 
 <a href="#view2">按钮1</a> 
 <div id="view1">视图1</div> 
 <div><a name="view2">视图2</a></div>

这种定位方式很简单,支持任意标签的定位,但是a标签的定位会改变路由的hash,如果有相关路由会进行路由跳转

使用js模拟锚点定位

通过js获取元素的scrollTop值,使其滚动到指定的位置,就能实现锚点定位效果,这里的tab切换选项,用到是的element-ui的el-tabs组件,具体实现如下:

<!-- html -->
 <el-tabs v-model="activeName" type="card" @tab-click="tabClick">
  <el-tab-pane :label="item.name" :name="item.key" v-for="item in tabList" :key="item.key"></el-tab-pane>
</el-tabs>
<!-- js -->
methods:{
 //获取当前元素的offsetTop
 getOffsetTop(obj) {
  let offsetTop = 0;
  while (obj != window.document.body && obj != null) {
  offsetTop += obj.offsetTop;
  obj = obj.offsetParent;
 }
  return offsetTop;
 },
 <!--锚点点击事件-->
 <!--fixedHeight 滚动的位置上方固定的高度-->
 tabClick(e) {
  let _this = this;
  //获取当前选中的index以便后面滚动高亮
  this.index = parseInt(e.index);
  //给定一个标识,锚点事件不触发滚动
  this.isScroll = false;
  this.isChange = false;
  //获取当前选中元素的top值(给元素绑定对应的ref值)
  let offsetTop = this.getOffsetTop(this.$refs[this.activeName]);
  let scrollTop = offsetTop - this.fixedHeight;
  window.scrollTo({
    top: scrollTop
  });
}

不得不提的一个方法就是scrollIntoView,Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内,同时还支持动态效果,但是不支持配置滚动到距离顶部的距离,会出现遮罩现象,但是很适合做会到顶部的功能

滚动高亮按钮

当用户滚动内容区时,高亮距离按钮组件最近的那个元素所对应的按钮。 通过监听滚动事件,获取当前选中的tab的offsetTop值和当前页面的scrollTop值,判断向上或者向下滚动,做出不同的处理,具体如下:

//页面滚动要做的事情
handleScroll() {
  let scrollTop =
    window.pageYOffset ||
    document.documentElement.scrollTop ||
    document.body.scrollTop;
   this.scrollTop = scrollTop;
   <!--isScroll 用于避免锚点事件触发页面滚动-->
   if (!this.isScroll) return;
   /**
    * scrollTop 页面的滚动条的高度
    * offsetTop 当前选中的tab元素的offsetTop
    * offsetHeight 当前选中元素的高度
    */
   let offsetTop = this.getOffsetTop(this.$refs[this.activeName]);
   let offsetHeight = this.$refs[this.activeName].offsetHeight;
   let actuaTop = scrollTop + this.fixedHeight;
   let length = this.tabList.length;
   /**
    * 页面滚动中根据相应位置变换选中tab
    */
   if (actuaTop < offsetTop && this.index > 0) {
    this.index = this.index - 1;
    this.activeName = this.tabList[this.index].key;
   } else if (this.index < length && actuaTop > offsetTop + offsetHeight) {
    this.index = this.index + 1;
    this.activeName = this.tabList[this.index].key;
 }
}

性能优化

页面中读取属性会导致页面reflow(下次会对导致页面reflow和repaint 的操作做一个总结),过度的reflow会导致页面性能下降,所以我们应该尽量减少reflow的次数,以便给用户更好的体验。 如果产品可以接受效果有延迟,就可以使用节流函数控制在一定时间内只执行一次函数(节流函数可以使用lodash.js 封装好的 throttle 方法)

总结

写到这里,需求中的三个功能都已经实现,也许还存在更好的方案,但是通过这次实现这三个需求,如果大家有其他更好的方法,欢迎留言补充,但我也从中学习到了一些东西 1.position:sticky的用法和使用条件

2.scrollTop、offsetTop等元素的相关属性、getBoundingClientRect()用法和 scrollTo、scrollIntoView的用法 3.锚点时间和滚动高亮事件导致的冲突处理等

以上所述是小编给大家介绍的vue实现吸顶、锚点和滚动高亮按钮效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
会自动逐行上升的文本框
Jun 30 Javascript
JAVASCRIPT HashTable
Jan 22 Javascript
jQuery 使用手册(三)
Sep 23 Javascript
JavaScript 高效运行代码分析
Mar 18 Javascript
GridView中获取被点击行中的DropDownList和TextBox中的值
Jul 18 Javascript
为开发者准备的10款最好的jQuery日历插件
Feb 04 Javascript
javascript中$(function() {});写与不写有哪些区别
Aug 10 Javascript
利用Javascript实现BMI计算器
Aug 16 Javascript
Angularjs手动解析表达式($parse)
Oct 12 Javascript
vue-router单页面路由
Jun 17 Javascript
jQuery实现的点击按钮改变样式功能示例
Jul 21 jQuery
javascript面向对象三大特征之封装实例详解
Jul 24 Javascript
vue-cli基础配置及webpack配置修改的完整步骤
Oct 20 #Javascript
关于Vue中axios的封装实例详解
Oct 20 #Javascript
JavaScript相等运算符的九条规则示例详解
Oct 20 #Javascript
Vue.js下拉菜单组件使用方法详解
Oct 19 #Javascript
vue实现二级导航栏效果
Oct 19 #Javascript
vue.js实现二级菜单效果
Oct 19 #Javascript
vue实现多级菜单效果
Oct 19 #Javascript
You might like
PHP中实现图片的锐化
2006/10/09 PHP
PHP通用检测函数集合
2006/11/25 PHP
利用curl 多线程 模拟 并发的详解
2013/06/14 PHP
PHP魔术方法的使用示例
2015/06/23 PHP
Yii多表联合查询操作详解
2016/06/02 PHP
thinkphp实现把数据库中的列的值存到下拉框中的方法
2017/01/20 PHP
php实现算术验证码功能
2018/12/05 PHP
jquery鼠标停止移动事件
2013/12/21 Javascript
JS获取select-option-text_value的方法
2013/12/26 Javascript
jQuery中clearQueue()方法用法实例
2014/12/29 Javascript
jQuery背景插件backstretch使用指南
2015/04/21 Javascript
基于JavaScript如何制作遮罩层对话框
2016/01/26 Javascript
详解jquery validate实现表单验证 (正则表达式)
2017/01/18 Javascript
vue+element实现表单校验功能
2019/05/20 Javascript
react实现同页面三级跳转路由布局
2019/09/26 Javascript
使用webpack将ES6转化ES5的实现方法
2019/10/13 Javascript
java遇到微信小程序 &quot;支付验证签名失败&quot; 问题解决
2019/12/22 Javascript
在Python的setuptools框架下生成egg的教程
2015/04/13 Python
Python3读取文件常用方法实例分析
2015/05/22 Python
基于Python如何使用AIML搭建聊天机器人
2016/01/27 Python
python paramiko模块学习分享
2017/08/23 Python
numpy 进行数组拼接,分别在行和列上合并的实例
2018/05/08 Python
python实现雨滴下落到地面效果
2018/06/21 Python
Django restframework 源码分析之认证详解
2019/02/22 Python
python3下载抖音视频的完整代码
2019/06/05 Python
Python-while 计算100以内奇数和的方法
2019/06/11 Python
Python程序打包工具py2exe和PyInstaller详解
2019/06/28 Python
python 下 CMake 安装配置 OPENCV 4.1.1的方法
2019/09/30 Python
Python中join()函数多种操作代码实例
2020/01/13 Python
小学生竞选班干部演讲稿
2014/04/24 职场文书
电台编导求职信
2014/05/06 职场文书
跳蚤市场口号
2014/06/13 职场文书
习近平在党的群众路线教育实践活动总结大会上的讲话全文
2014/10/25 职场文书
青年文明号汇报材料
2014/12/23 职场文书
2015年营业员工作总结
2015/04/23 职场文书
关于Redis的主从复制及哨兵问题
2022/06/16 Redis