• 【Vue项目复习笔记】标题和内容的联动效果


    这个功能就是点击了商品就跳到商品对应的位置,点击了参数就跳到参数对应的位置等。以及上下内容的联动效果。

    点击标题,滚动到对应的主题

    第一步是要监听DetailNavBar的点击

      methods:{
        titleClick(index){
          this.currentIndex=index;
          this.$emit('titleClick',index)
          },
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将这个点击事件发出去,在Detail中

     <detail-nav-bar class="detail-nav" @titleClick="titleClick"></detail-nav-bar>
    
    • 1

    在methods中

      titleClick(index){
          this.$refs.scroll.scroll.scrollTo(0, y, 200);
        },
    
    • 1
    • 2
    • 3

    主要是这里的y值的获取;
    先在data()里增加一个变量

      themeTopYs:[],
    
    • 1

    这个变量里面有4个值,分别对应小标题的滚动位置。那滚动到多少呢?
    就需要获取对应的offsetTop,那怎么动态的获取对应的offsetTop呢?
    我们先看mouted()里面是否可以拿到值

      mounted() {
        this.themeTopYs.push(0);
        this.themeTopYs.push(参数的OffsetTop);
        this.themeTopYs.push(评论的OffsetTop);
        this.themeTopYs.push(推荐的OffsetTop);
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么参数还有其他的offsetTop怎么获取呢?
    要添加对应的ref

    <detail-param-info  ref="param" :param-info="paramInfo" ></detail-param-info>
        <detail-comment-info ref="comment" :comment-info="commentInfo" ></detail-comment-info>
        <goods-list  ref="recommend"  :goods="recommends"></goods-list>
    
    • 1
    • 2
    • 3

    分别为其添加对应的ref,上面的代码就变成

    mounted() {
        this.themeTopYs.push(0);
        this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
        this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
        this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们打印输出一下会发现:
    在这里插入图片描述
    拿到的东西有3个都是undefined,意味着上面的el里面没有东西,因为我们之前在DetailParamInfo还有其他两个组将上面都做了一个判断

     <div class="param-info" v-if="Object.keys(paramInfo).length !== 0">
    
    • 1

    只有我们paramInfo里面有值才会渲染页面,意味着它还没有请求数据,不能保证在mouted里面数据就能请求下来,这个不一定。因为在created里面才开始请求,在mouted里面数据不一定到。$el去拿组件的根组件,我们又做了一个判断,没有数据之前,根组件也不会渲染。
    我们将其放到created()的getDetail函数里

    this.themeTopYs=[];
          this.themeTopYs.push(0);
          this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
          this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
          this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们会发现其打印输出仍然没有值,因为要等我们把数据赋值过去以后,稍微等一会儿,等它把页面渲染完以后,才能保证它有值。那该怎么做呢?
    有一个叫做this.$nextTick(),它就可以等到页面渲染完以后,回调一次后面的箭头函数。就可以保证他们都有值。

       this.$nextTick(()=>{
            this.themeTopYs=[];
            this.themeTopYs.push(0);
            this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
            this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
            this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
          })
        }),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    打印输出
    在这里插入图片描述
    原因如下:

        // 第一次获取,值不对
        // 原因是:this.$refs.param.$el压根没有渲染
        this.themeTopYs=[];
        this.themeTopYs.push(0);
        this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
        this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
        this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
        console.log(this.themeTopYs);
    
       this.$nextTick(()=>{
            //第二次获取:值不对
            //值不对的原因是图片没有计算在内
            //根据最新的数据,对应的DOM是已经被渲染出来了
            //但是图片依然没有加载完(目前获取到的offsetTop不包含其中的图片)
            //offsetTop值不对的时候,都是因为图片的问题
            this.themeTopYs=[];
    
            this.themeTopYs.push(0);
            this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
            this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
            this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
          })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这两次获取均没有值,我们可以用如下办法:
    详页的图片加载完以后可以在methods中的imageLoad()方法里面做一个回调,然后我们在回调里面每次都来获取一次

    imageLoad(){
          this.$refs.scroll.scroll.refresh()
        
          this.themeTopYs=[];
          this.themeTopYs.push(0);
          this.themeTopYs.push(this.$refs.param.$el.OffsetTop);
          this.themeTopYs.push(this.$refs.comment.$el.OffsetTop);
          this.themeTopYs.push(this.$refs.recommend.$el.OffsetTop);
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个时候,这里面的值肯定会调用很频繁,但是结果一定是对的

    对于此时调用特别频繁我们可以用防抖函数
    先在data()里面增加一个变量:

    getThemeTopY:null,
    
    • 1

    在created()里面

       //4.给getThemeTopY赋值
            this.getThemeTopY = debounce(() => {
              this.themeTopYs = [];
              this.themeTopYs.push(0);
              this.themeTopYs.push(this.$refs.param.$el.offsetTop);
              this.themeTopYs.push(this.$refs.comment.$el.offsetTop);
              this.themeTopYs.push(this.$refs.recommend.$el.offsetTop);
              // console.log(this.themeTopYs);
            }, 100);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    最后在methods中的imageLoad()里

      imageLoad(){
          this.$refs.scroll.scroll.refresh()
          this.getThemeTopY()
        },
    
    • 1
    • 2
    • 3
    • 4

    最终结果是:
    请添加图片描述
    总结:
    点击标题,滚动到对应的主题

    ●在detail中监听标题的点击,获取index
    ●滚动到对应的主题:

    • 获取所有主题的offsetTop
    • 问题:在哪里才能获取到正确的offsetTop
      • 1.created肯定不行,压根不能获取元素
      • 2.mounted也不行, 数据还没有获取到
      • 3.获取到数据的回调中也不行, DOM还没有渲染完
      • 4.$nextTick也不行,因为图片的高度没有被计算在内
      • 5.在图片加载完成后,获取的高度才是正确

    滚动内容显示对应的标题

    获取滚动位置,这就需要监听滚动。也就是监听scroll事件,它又发出过一个事件

      // 2.监听滚动的位置
        this.scroll.on('scroll', (position) => {
          // console.log(position);
          this.$emit('scroll', position)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    所以我们要做的就是在Detail终接收这个事件

    <scroll class="content" ref="scroll" @scroll="contentScroll">
    
    • 1

    在methods中

       contentScroll(position){
          console.log(position);
            }
    
    • 1
    • 2
    • 3

    此时控制台并没有打印内容,原因是在我们的scroll里面,默认情况下我们的0,0的时候就默认不派发这个事件

     probeType: {
          type: Number,
          default: 0
        },
    
    • 1
    • 2
    • 3
    • 4

    为了能让它派发事件,我们需要传入一个probe-type的值

     <scroll class="content" ref="scroll" :probe-type="3" @scroll="contentScroll" >
    
    • 1

    此时
    请添加图片描述
    我们主要是想要获取y值

    positoinY和主题中值进行对比 比如说我们的四个参数的值分别为[0, 7938, 9120, 9452 ]
    positoinY在0和7938之间,index=0
    positoinY在7938和9120 之间,index = 1
    positoinY 在9120和9452之间,index = 2
    positoinY 超过9120 值,index = 3

    我们先在data()里新增一个变量:

      currentIndex:0,
    
    • 1

    然后在methods中

       contentScroll(position){
          // console.log(position);
          // 1、获取y值
          const positionY=-position.y
          //2、positionY和主题中值进行对比
          //  [0, 7938, 9120, 9452 ]
          //positoinY在0和7938之间,index=0
           // positoinY在7938和9120 之间,index = 1
           // positoinY 在9120和9452之间,index = 2
          // positoinY 超过9120 值,index = 3
    
          let length=this.themeTopYs.length
          for(let i=0;i<length-1;i++){
            // if(this.currentIndex!==i && ((i= this.themeTopYs[i] &&
            //   positionY< this.themeTopYs[i+1]) || (i===length-1 && positionY >= this.themeTopYs[i]))){
            if(this.currentIndex!==i && (positionY>=this.themeTopYs[i] && positionY<=this.themeTopYs[i+1])){
              this.currentIndex=i;
              this.$refs.nav.currentIndex=this.currentIndex
            }
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    其中要给我们的头部导航栏一个nav,让其对应的currentIndex一致。
    我们的判断条件其中的条件一:

    条件一:this.currentIndex! == i 目的是防止赋值的过程过于频繁
    条件二: ((i= this.themeTopYs[i] &&
    positionY< this.themeTopYs[i+1]) || (i== =length-1 && positionY >= this.themeTopYs[i])))
    条件1:(i= this.themeTopYs[i] &&
    positionY< this.themeTopYs[i+1])
    条件2: ( i = = = length-1 && positionY >= this.themeTopYs[i])
    其中条件1是用来判断区间:在0和某个数字之间((i ===length-1 )
    条件2是用来判断大于等于: i = = = length-1

    我们下面来做一个优化(hack做法):
    我们最后在加上一个非常大的值,让其简化我们的判断条件
    在created里面push五个值,其中一个就是最大值

    this.themeTopYs.push(Number.MAX_VALUE);
    
    • 1

    然后我们的判断条件就可以简化的写成

    positionY>=this.themeTopYs[i] && positionY<=this.themeTopYs[i+1]
    
    • 1

    考虑到越界的问题,我们将循环里面的length-1。
    多占了一些空间,但是提高了性能。

    最终的结果:
    请添加图片描述

  • 相关阅读:
    【Java编程进阶】Java开发环境搭建
    CNI、CSI 和 CRI在 Docker 中的角色和作用
    MATLAB中scatter3函数用法
    最新OPPO 真我手机 一加手机 使用adb命令永久关闭系统更新教程
    OS 进程同步
    权限提升数据库(基于MySQL的UDF,MOF,启动项提权)
    查看进程与对应的线程
    设计模式——迭代器模式(Iterator Pattern)+ Spring相关源码
    基于SSM的邮箱客户端的设计与实现
    猫树详解
  • 原文地址:https://blog.csdn.net/qq_40992225/article/details/126255174