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 相关文章推荐
一个用js实现控制台控件的代码
Sep 04 Javascript
js chrome浏览器判断代码
Mar 28 Javascript
离开页面时检测表单元素是否被修改,提示保存的js代码
Aug 25 Javascript
jquerydom对象的事件隐藏显示和对象数组示例
Dec 10 Javascript
javascript控制在光标位置插入文字适合表情的插入
Jun 09 Javascript
jQuery切换所有复选框选中状态的方法
Jul 02 Javascript
jQuery实现的超酷苹果风格图标滑出菜单效果代码
Sep 16 Javascript
js实现创建删除html元素小结
Sep 30 Javascript
AngularJS 指令详细介绍
Jul 27 Javascript
Vue开发过程中遇到的疑惑知识点总结
Jan 20 Javascript
vue 组件高级用法实例详解
Apr 11 Javascript
使用Angular自定义字段校验指令的方法示例
Feb 01 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 多行多列显示
2009/08/15 PHP
超级实用的7个PHP代码片段分享
2012/01/05 PHP
PHP的几个常用加密函数
2016/02/03 PHP
appendChild() 或 insertBefore()使用与区别介绍
2013/10/11 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
JavaScript数组去重的3种方法和代码实例
2015/07/01 Javascript
JQ技术实现注册页面带有校验密码强度
2015/07/27 Javascript
vue指令以及dom操作详解
2017/03/04 Javascript
Bootstrap.css与layDate日期选择样式起冲突的解决办法
2017/04/07 Javascript
原生JS 购物车及购物页面的cookie使用方法
2017/08/21 Javascript
详解vue-cli+es6引入es5写的js(两种方法)
2019/04/19 Javascript
原生javascript单例模式的应用实例分析
2020/02/23 Javascript
Python中用max()方法求最大值的介绍
2015/05/15 Python
python enumerate函数的使用方法总结
2017/11/15 Python
Python2.7 实现引入自己写的类方法
2018/04/29 Python
Python工厂函数用法实例分析
2018/05/14 Python
将python文件打包成EXE应用程序的方法
2019/05/22 Python
python实现智能语音天气预报
2019/12/02 Python
python实现学生管理系统开发
2020/07/24 Python
Python 制作查询商品历史价格的小工具
2020/10/20 Python
安装Anaconda3及使用Jupyter的方法
2020/10/27 Python
python爬虫爬取淘宝商品比价(附淘宝反爬虫机制解决小办法)
2020/12/03 Python
Canvas制作的下雨动画的示例
2018/03/06 HTML / CSS
印度首个本地在线平台:nearbuy
2019/03/28 全球购物
公务员培训心得体会
2013/12/28 职场文书
小学生元旦感言
2014/02/26 职场文书
大学班级计划书
2014/04/29 职场文书
经典团队口号
2014/06/06 职场文书
党员应该树立反腐倡廉的坚定意识思想汇报
2014/09/12 职场文书
庆祝教师节标语
2014/10/09 职场文书
电影焦裕禄观后感
2015/06/09 职场文书
《叶问2》观后感
2015/06/15 职场文书
小学生暑假安全公约
2015/07/14 职场文书
Java Kafka 消费积压监控的示例代码
2021/07/01 Java/Android
python中出现invalid syntax报错的几种原因分析
2022/02/12 Python
MySQL深分页问题解决思路
2022/12/24 MySQL