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实现addClass,removeClass,hasClass的函数代码
Jul 13 Javascript
没有document.getElementByName方法
Aug 19 Javascript
JS实现在网页中弹出一个输入框的方法
Mar 03 Javascript
javascript事件处理模型实例说明
May 31 Javascript
Jquery调用iframe父页面中的元素及方法
Aug 23 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
Nov 30 Javascript
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
Mar 23 jQuery
js 事件的传播机制(实例讲解)
Jul 20 Javascript
JavaScript实现汉字转换为拼音及缩写的方法示例
Mar 28 Javascript
jenkins自动构建发布vue项目的方法步骤
Jan 04 Vue.js
原生JavaScript实现轮播图
Jan 10 Javascript
(开源)微信小程序+mqtt,esp8266温湿度读取
Apr 02 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 session常见问题集锦及解决办法总结
2007/03/18 PHP
header导出Excel应用示例
2014/01/24 PHP
php5.2以下版本无json_decode函数的解决方法
2014/05/25 PHP
php实现CSV文件导入和导出
2015/10/24 PHP
twig里使用js变量的方法
2016/02/05 PHP
php静态成员方法和静态的成员属性的使用方法
2017/10/26 PHP
JavaScript网页制作特殊效果用随机数
2007/05/22 Javascript
textarea中的手动换行处理的jquery代码
2011/02/26 Javascript
js自定义事件及事件交互原理概述(一)
2013/02/01 Javascript
JS数组的赋值介绍
2014/03/10 Javascript
ExtJS中设置下拉列表框不可编辑的方法
2014/05/07 Javascript
与Math.pow 相反的函数使用介绍
2014/08/04 Javascript
JavaScript拆分字符串时产生空字符的解决方案
2014/09/26 Javascript
JQuery中Text方法用法实例分析
2015/05/18 Javascript
JavaScript获取客户端IP的方法(新方法)
2016/03/11 Javascript
微信小程序 Page()函数详解
2016/10/17 Javascript
react系列从零开始_简单谈谈react
2017/07/06 Javascript
angularJs中json数据转换与本地存储的实例
2018/10/08 Javascript
微信小程序实现商品属性联动选择
2019/02/15 Javascript
JS实现查找数组中对象的属性值是否存在示例
2019/05/24 Javascript
详解JavaScript原型与原型链
2020/11/16 Javascript
[01:18]DOTA2超级联赛专访hanci ForLove淘汰感言曝光
2013/06/04 DOTA
python3.3教程之模拟百度登陆代码分享
2014/01/16 Python
Python使用urllib2模块抓取HTML页面资源的实例分享
2016/05/03 Python
PyQt 线程类 QThread使用详解
2017/07/16 Python
Python基于回溯法子集树模板解决野人与传教士问题示例
2017/09/11 Python
Python操作注册表详细步骤介绍
2020/02/05 Python
英国领先的瓷砖专家:Walls and Floors
2018/04/27 全球购物
可打印的优惠券、杂货和优惠券代码:Coupons.com
2018/06/12 全球购物
联想德国官网:Lenovo Germany
2018/07/04 全球购物
运动会演讲稿
2014/05/07 职场文书
关于感恩的演讲稿500字
2014/08/26 职场文书
街道社区活动报告
2015/02/05 职场文书
2015年入党积极分子评语
2015/03/26 职场文书
详解CSS故障艺术
2021/05/25 HTML / CSS
浅谈pytorch中的dropout的概率p
2021/05/27 Python