热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue项目中实现导航栏锚点效果

需求:   vue项目PC端详情页内容过多,在右侧或左侧加一个导航栏,通过点击某一项,页面平滑滚动到具体的内容上。并把这个功能封装成组件。 思路

需求:
  vue项目PC端详情页内容过多,在右侧或左侧加一个导航栏,通过点击某一项,页面平滑滚动到具体的内容上。并把这个功能封装成组件。

在这里插入图片描述

思路:

  1. 封装成组件复用的话,首先快捷键的每一项数据需要父组件传入;在父组件定义一个数组作为右侧导航栏的数据;由于左侧区域的某一块内容没有数据时,其对应的导航项不显示;
  2. 要给每一块的内容最外层绑定ref,是为了获取该dom元素,通过点击导航栏某一项时,让页面可以滚动到对应的元素内容;
  3. 导航在抽屉里做的,给最外层绑定ref=“drawer”,可以获取到当前页面最外层的dom元素,根据最外层容器的dom元素来获取滚动高度;
  4. 组件要接收导航栏数据、接收当前是否是抽屉(默认为抽屉,传false为普通正常页面)、接收当前页面所有的dom元素、接收样式(显示在页面的左侧还是右侧)
  5. 统一封装滚动方法:将滚动方法放在定时器中,在获取到最新DOM元素时,添加该定时器;在组件销毁时,清除定时器;定时器中主要功能:当滚动上去的高度+可见区域的高度==全文高度,导航栏选中最后一项;当第一项的距离可视窗口顶部距离>0,导航栏选中第一项。
  6. 点击方法:点击导航栏某一项,内容区域滚动到可视区域的顶部,导航栏选中该项。

代码:

具体页面
在这里插入图片描述

组件:

<template><div><div class&#61;"leftKey" :style&#61;"{ left: left || &#39;auto&#39;, right: right || &#39;auto&#39;, opacity: opacity }"><span v-for&#61;"item in titleKey" :key&#61;"item.id"><a v-if&#61;"item.flag" &#64;click&#61;"goAnchor(item.id)" :class&#61;"{checkKey: item.checked}">{{item.name}}</a></span></div></div>
</template><script>
export default {data () {return {timer: null,scrollTop: 0,anchorFlag: false,ids: &#39;&#39;}},created () {// 在组件调用之前将所有项设置未选中&#xff0c;将第一项设置默认选中this.titleKey.forEach(item &#61;> {item.checked &#61; false})this.titleKey[0].checked &#61; true},mounted () {// console.log(&#39;7777&#39;, this.parentRef)this.fun &#61; () &#61;> {clearTimeout(this.timer)this.timer &#61; setTimeout(() &#61;> {// scrollTop 网页被卷去的高// clientHeight 网页可见区域高// scrollHeight 网页正文全文高// this.parentRef.drawer.$refs.drawer.scrollTop 获取当前抽屉滚动的高度// document.documentElement.scrollTop || document.body.scrollTop 获取当前页面滚动的高度var scrollTop &#61; this.drawerFLag ? this.parentRef.drawer.$refs.drawer.scrollTop : (document.documentElement.scrollTop || document.body.scrollTop)var clientHeight &#61; document.documentElement.clientHeight || document.body.clientHeightvar scrollHeight &#61; this.drawerFLag ? this.parentRef.drawer.$refs.drawer.scrollHeight : (document.documentElement.scrollHeight || document.body.scrollHeight)this.scrollTop &#61; scrollTop// 网页被卷去的高&#43;网页可见的高&#61;&#61;&#61;网页全文高&#xff0c;就是滚动到最底部了&#xff0c;默认选中最后一项// 为什么不能使用forEach循环&#xff0c;因为最后一项可能是false不显示&#xff0c;这个时候如果只遍历将全部设置为false&#xff0c;而把最后一项设为true此时没有可选中的项// 设置一个变量为true&#xff0c;倒着遍历&#xff0c;若该项存在且变量为true&#xff0c;则将这一项设置为true&#xff0c;将变量设置为false&#xff1b;剩下的for循环会将每一项都设为falseif (scrollTop &#43; clientHeight &#61;&#61;&#61; scrollHeight) {let lastFlag &#61; truefor (let i &#61; this.titleKey.length - 1; i >&#61; 0; i--) {if (this.titleKey[i].flag && lastFlag) {this.titleKey[i].checked &#61; truelastFlag &#61; false} else {this.titleKey[i].checked &#61; false}}return}// 监听id对应DOM与屏幕顶部的距离&#xff0c;第一项距离大于0&#xff0c;就默认选中第一项// getBoundingClientRect().top 元素的上边 距离 可视窗口顶部的距离if (this.parentRef[this.titleKey[0].id].getBoundingClientRect().top > 0) {this.titleKey.forEach(item &#61;> {item.checked &#61; false})this.titleKey[0].checked &#61; true}}, 50)}// vue使用$once清除定时器的问题&#xff0c;以防其他页面滚动时触发该定时器导致报错// 通过$once来监听生命周期beforeDestroy钩子&#xff0c;在组件销毁前清除定时器this.$once(&#39;hook:beforeDestroy&#39;, () &#61;> {window.removeEventListener(&#39;scroll&#39;, this.fun, true)})// 通过$nextTick获取最新更新的DOM元素this.$nextTick(() &#61;> {window.addEventListener(&#39;scroll&#39;,this.fun,true)})},methods: {// 点击导航栏的某一项&#xff0c;左侧内容区域滚动到对应的位置goAnchor (id) {// 如果点击选中的这一项id在传过来的dom元素中// scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内// 让选中id对应的DOM置顶&#xff0c;即DOM与可视屏幕顶部重合if (this.parentRef[id]) {this.parentRef[id].scrollIntoView({// 平滑过渡behavior: &#39;smooth&#39;,// 上边框与视窗顶部平齐。默认值block: &#39;start&#39;})// 遍历让所有项为false,点击项为truethis.titleKey.forEach(item &#61;> {if (item.id &#61;&#61;&#61; id) {item.checked &#61; true} else {item.checked &#61; false}})}},},props: {// 父组件传入的数据属性名titleKey: {// 类型type: Array,// 默认值default: () &#61;> []},// 父组件传来的值是否是抽屉// 默认是true也就是抽屉&#xff0c;如果不是则传falsedrawerFLag: {type: Boolean,default: true},// 父组件的refparentRef: {type: Object,default: () &#61;> {}},// 居左显示left: {type: String,default: &#39;&#39;},// 居右显示right: {type: String,default: &#39;&#39;},// 设置透明度opacity: {type: Number,default: 0}}
}
</script><style lang&#61;"scss" scoped>
&#64;import "~&#64;/styles/variables.scss";
&#64;import "~&#64;/styles/index.scss";.clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/content: "";display: block;height: 0;clear:both;visibility: hidden;}.clearfix{*zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行&#xff0c;其他浏览器不执行*/}.checkKey {color: #E8380D;border-bottom: 1px solid #E8380D;background-color: #E7370D;color: #fff;}.leftKey {position: fixed;width: 127px;background: #fff;box-shadow:0px 3px 8px 1px rgba(12,12,12,0.06);font-size: 14px;color: #333;background-color: rgba(255,252,252,1);top: 115px;z-index: 999;a {display: block;padding: 16px 0px 16px 21px;border-top: 1px solid rgba(255,228,222,1);border-left: 1px solid rgba(255,228,222,1);border-right: 1px solid rgba(255,228,222,1);}a:last-child {border-bottom: 1px solid rgba(255,228,222,1);}img {padding-right: 2px;}}</style>

main.js

import Vue from &#39;vue&#39;
import ElementUI from &#39;element-ui&#39;
// 全局注册导航栏组件
import shortcutKey from &#39;&#64;/components/ ShortcutKey&#39;Vue.component(&#39;ymShortcutKey&#39;, shortcutKey)Vue.config.productionTip &#61; false
Vue.use(ElementUI)new Vue({el: &#39;#app&#39;,router,store,render: h &#61;> h(App)
})

参考文章&#xff1a;Vue中实现锚点

涉及知识&#xff1a;

  1. vue使用$once清除定时器

    mounted () {const that &#61; this// 设置定时器const testSetinterval &#61; setInterval(() &#61;> {setTimeout(() &#61;> {console.log(&#39;test clearInterval&#39;)}, 0)}, 2000)// 通过$once来监听生命周期beforeDestroy钩子&#xff0c;在组件销毁前清除定时器。this.$once(&#39;hook:beforeDestroy&#39;, () &#61;> {clearInterval(testSetinterval)})},

    参考&#xff1a;
      vue使用$once清除定时器的问题
      vue中如何清除定时器

  2. scrollTop 网页被卷去的高
    clientHeight 网页可见区域高
    scrollHeight 网页正文全文高

    参考&#xff1a;
      搞清clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop
      DOM元素位置&#xff0c;滚动位置和鼠标事件位置相关属性函数总结
      获取页面滚动高度
      document.documentElement.scrollTop || document.body.scrollTop;

  3. this.$nextTick()

    this.$nextTick()这个方法作用是当数据被修改后使用这个方法会回调获取更新后的dom再render出来(调用render()函数&#xff0c;重新编译。将vue模版里的逻辑如v-if、v-for等这些内容是浏览器不能识别的&#xff0c;必须通过js去转换为html&#xff0c;才能够显示页面。)

    参考&#xff1a;
      对vue实现数据实时更新&#xff0c;render() 函数的一些理解
      个人理解this.$nextTick()的使用场景

      this.$nextTick

  4. ref$refs
    使用ref绑定DOM元素&#xff0c;通过this.$refs获取绑定的该元素。这样可以减少获取dom节点的消耗

    <input type&#61;"text" ref&#61;"input1"/>
    this.$refs.input1.value &#61;"22";

    参考&#xff1a;$refs基本用法
    Vue基础4&#xff1a; ref 和 $refs

  5. setInterval()setTimeout()
    setInterval的特点&#xff1a;一直循环调用函数&#xff0c;不会自己停止&#xff1b;需要用window.clearInterval(setInt);这个函数去停止循环
    setTimeout的特点&#xff1a;只调用一次
    setTimeout(“showTime()”,5000); //延迟5秒刷新页面
    业务场景&#xff1a;
    setTimeout用于延迟执行某方法或功能
    setInterval则一般用于刷新表单&#xff0c;对于一些表单的假实时指定时间刷新同步

    参考&#xff1a;
    setInterval()与setTimeout()计时器
    setTimeout和setInterval的区别
    setInterval和setTimeout的区别


推荐阅读
  • Vue生产环境调试的方法步骤
    开发环境下Vue会提供很多警告来帮你对付常见的错误与陷阱,而在生产环境下,这些警告语句却没有用,反而会增加应用的体积,下面这篇文章主要给大家介绍了关于Vue生产环境调试的方法步骤, ... [详细]
  • domain.js代码如下 ... [详细]
  • Sets和数组一样,都是一些有序值的的集合,但是Sets和数组又有所不同,首先Sets集合中不能存有相同的值,如果你向Set ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • 使用RSACryptoServiceProvider进行公钥加密我已经在CodeProject上发表了一篇文章,解释了如何使用RSA提供程序进行加密和解密:RSA私钥加密虽然200 ... [详细]
  • Ithinkthishasbeenupbefore,butcouldntfindanyanswertoit.Ifitsalreadyansweredplease ... [详细]
  • 标签PostgreSQL,Linux,perf,性能诊断,stap,systemtap,strace,dtrace,dwarf,profiler,perf_events,probe ... [详细]
  • 一、vue介绍Vue.js是一套构建用户界面(UI)的渐进式JavaScript框架,是一个轻量级MVVM(model-view-viewModel&# ... [详细]
  • Lodash中文文档(v3.10.1)–“Collection”要领TranslatedbyPeckZegOriginalDocs:Lodashv3.10.1Docs乞助翻译文档的 ... [详细]
  • JS加密解密
    leta=汪政..222RRRp767868^*%^*%344h哈哈;letb=udp.d(ud(a));//需要加密的内容letc=udp. ... [详细]
  • 大数据学习环境安装关于防火墙​centos7使用的是firewalld,centos之前使用的是iptablesCentOS7关闭防火墙查看防火墙状态sudosy ... [详细]
  • 史上最全的Websocket入门教程
    websocket是什么?答:它是一种网络通信协议,是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。为什么需要websocket?疑问?我 ... [详细]
  • 关于初学PHP时的知识积累总结【PHP】
    后端开发|php教程PHP,知识积累后端开发-php教程PHP基础A、初识PHPPHP是与HTML混合使用的嵌入式语言。1、PHP标记默认标记短标记,需在php.ini中将shor ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
author-avatar
手机用户2502870941
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有