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 相关文章推荐
Javascript Request获取请求参数如何实现
Nov 28 Javascript
js实现完全自定义可带多级目录的网页鼠标右键菜单方法
Feb 28 Javascript
原生js实现数字字母混合验证码的简单实例
Dec 10 Javascript
javascript设计模式之模块模式学习笔记
Feb 15 Javascript
Angularjs根据json文件动态生成路由状态的实现方法
Apr 17 Javascript
判断颜色是否合法的正则表达式(详解)
May 03 Javascript
Javascript(es2016) import和require用法和区别详解
Aug 11 Javascript
Vue2.0 axios前后端登陆拦截器(实例讲解)
Oct 27 Javascript
arctext.js实现文字平滑弯曲弧形效果的插件
May 13 Javascript
如何通过shell脚本自动生成vue文件详解
Sep 10 Javascript
js仿淘宝放大镜效果
Dec 28 Javascript
vue 实现上传组件
May 31 Vue.js
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
怎样在UNIX系统下安装MySQL
2006/10/09 PHP
简体中文转换为繁体中文的PHP函数
2006/10/09 PHP
PHP中的日期及时间
2006/11/23 PHP
PHP学习之数组值的操作
2011/04/17 PHP
php 字符串压缩方法比较示例
2014/01/23 PHP
配置php.ini实现PHP文件上传功能
2014/11/27 PHP
使用PHP接受文件并获得其后缀名的方法
2015/08/05 PHP
日常整理PHP中简单的图形处理(经典)
2015/10/26 PHP
详解CSS样式中的 !important * _ 符号
2021/03/09 HTML / CSS
Javascript 面向对象 继承
2010/05/13 Javascript
JQuery live函数
2010/12/24 Javascript
JQuery入门——用bind方法绑定事件处理函数应用介绍
2013/02/05 Javascript
js获取或设置当前窗口url参数的小例子
2013/10/14 Javascript
JavaScript实现数据类型的相互转换
2016/03/06 Javascript
jQuery设置和获取select、checkbox、radio的选中值方法
2017/01/01 Javascript
Node.js中.pfx后缀文件的处理方法
2017/03/10 Javascript
JavaScript多线程运行库Nexus.js详解
2017/12/22 Javascript
简单的Vue异步组件实例Demo
2017/12/27 Javascript
Vue波纹按钮组件制作
2018/04/30 Javascript
AngularJS 多指令Scope问题的解决
2018/10/25 Javascript
通过JavaScript下载文件到本地的方法(单文件)
2019/03/17 Javascript
Vue中通过vue-router实现命名视图的问题
2020/04/23 Javascript
原生JS实现拖拽功能
2020/12/16 Javascript
[01:02:02]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第二局
2016/02/25 DOTA
python批量生成本地ip地址的方法
2015/03/23 Python
python贪婪匹配以及多行匹配的实例讲解
2018/04/19 Python
香港太阳眼镜网上商店:SmartBuyGlasses香港
2016/07/22 全球购物
Paradigit比利时电脑卖场:购买笔记本、电脑、平板和外围设备
2016/11/28 全球购物
如何利用XMLHTTP检测URL及探测服务器信息
2013/11/10 面试题
为什么要使用servlet
2016/01/17 面试题
超级搞笑检讨书
2014/01/15 职场文书
汽车服务工程专业自荐信
2014/09/02 职场文书
2014年高中教师工作总结
2014/12/19 职场文书
合作协议书格式范本
2016/03/21 职场文书
文案策划岗位个人自我评价(范文)
2019/08/08 职场文书
Golang 入门 之url 包
2022/05/04 Golang