Vue + Better Scroll 楼层效果傻瓜包

npm init vue@latest

下载BetterScroll :

npm install @better-scroll/core --save

一.结构部分:

<template>
    <div class="container">     //最大的盒子
      <div class="left" ref="left_" @click="left_Click">    //左侧内容盒子
        <div class="left_">     //存在于左侧内容盒子内的滚动容器
          <p        
            v-for="(item, index) in leftList"   //循环数据并渲染
            :key="index"
            :class="index == activeIndex ? 'active' : ''"   //此处进行高亮判断
            :data-index="index"    //自定义属性因为是事件委托,拿不到点击的index所以自定义
          >
            {{ item }}
          </p>
        </div>
      </div>
      <div class="right" ref="right_">  //右侧内容盒子
        <div class="right_">     //存在于右侧内容盒子下的滚动容器
          <p v-for="(item, index) in leftList" :key="index">{{ item }}</p>   //循环数据并渲染
        </div>
      </div>
    </div>
  </template>

二.CSS部分:

.container {
    width: 100vw;
    height: 100vh;
    display: flex;
    overflow: hidden;
  }
  .left {
    width: 2.6667rem;
    flex: none;
    background-color: aqua;
  }
  .left p {
    width: 2.6667rem;
    height: 1.3333rem;
    background-color: aquamarine;
    text-align: center;
    line-height: 1.3333rem;
  }
  .right {
    flex: 1;
    background-color: pink;
  }
  .right p {
    height: 10.6667rem;
    background-color: hotpink;
    text-align: center;
    line-height: 10.6667rem;
    margin-bottom: 0.2667rem;
  }
  .left .active {
    color: white;
    background-color: red;
  }

三.JS部分:

 <script setup lang="ts">
    import { onMounted,ref } from "vue"
    import BScroll from "@better-scroll/core"   //引入Betterscroll核心包(并不是完整包)
    
    //此处进行JS原生的移动端适配(vite自带适配方案,而原生JS可以应对仍和环境勿忘)
    (function (window) {
        function setRem() {
            let width = window.document.documentElement.clientWidth;
            window.document.documentElement.style.fontSize = width / 10 + "px";
    }
    window.addEventListener("load", setRem);
    window.addEventListener("resize", setRem);
  })(window)
  
  //ref 获取dom元素
  const left_ = ref<any>(null)    //获取左侧内容盒子
  const right_ = ref<any>(null)   //获取右侧内容盒子
  
  //渲染数据,以下为模拟数据,由于左右数据目前一样,所以共用这一条数据
    const leftList = ref([
    "红米手机",
    "手机配件",
    "电脑平板",
    "智能穿戴",
    "电视",
    "大家电",
    "小家电",
    "智能家居",
    "出行运动",
    "日用百货",
    "儿童用品",
    "有品精选",
    "小米服务",
    "飞机大炮",
    "飙车一族",
    "鬼火少年",
    "鬼火少女",
  ]);
  
  //存放高亮的变量,用于三元判断
  const activeIndex = ref<string | number>(0);
  
  //开关变量,用于控制左侧是否高亮
  const flag = ref(false);
  
  //声明全局变量,用于存储左右两个内容盒子的BScroll实例
  let bs: any;          //左实例
  let bs1: any;         //有实例
  
  //bs实例
  const init = ()=>{      //声明初始化函数
    bs = new BScroll(left_.value, {     //用于左侧滚动实例
        probeType:3,                   //probeType:3是代表实时监听滚动条事件
        click:true,
    })
    bs1 = new BScroll(right_.value, {   //用于右侧滚动实例
        probeType:3,
        click:true,
    })
      //页面发生变化时,需要重新计算滚动区域的大小和位置
        bs.refresh()        
        bs1.refresh()
      //右侧滚动开始时将开关变量设置为ture,用来实现点击时直接高亮效果,如不设置会出现点击时高亮移动到点击位    置,而不是瞬间高亮与点击位置。 scrollStart是BScroll的滚动开始事件
        bs1.on("scrollStart", ()=>{
            flag.value = true
        })
        
      //右侧滚动时设置左侧高亮,y是盒子滚动的距离是负数
      bs1.on("scroll", function ({y}:{y:number})){
        if(flag.value){
            //ref的children是子标签的集合,拿到所有的p标签
            let RP = right_.value.children[0].children
            //y滚动的距离,现将负值变为正值
            let h = Math.abs(y)
            //循环所有p标签,判断p标签距离顶部的距离
            for(let i = 0;i < RP.length; i++){
                //如果小于60,就让左侧对应的高亮
                if(Math.abs(h - RP[i].offsetTop) < 60) {
                    //设置高亮,由于左右对应,所以i就是左侧数据的对应项
                    activeIndex.value = i
                    //使左侧滚动到相应元素,scrollToElement是BS方法,滚动到目标指定元素
                    //而已经指定为left_.value.children[0].children[activeIndex.value],
                    //所以会自动滚动到视口最上方
                    bs.scrollToElement(
                        left_.value.children[0].children[activeIndex.value],
                        1000,
                        false,
                        false
                    )
                }
            }
        }
      }
  }
  
  //左侧点击事件
  const left_Click = (e:MouseEvent) => {
    let dom = e.target as HTMLParagraphElement        //用来存放点击的元素
    const Lp = left_.value.children[0].children       //获取左边所有的p标签
    flag.value = false                              //修改开关变量
    if(flag.value) {                
        for(let i = 0;i < Lp.length; i++){                  //循环p标签,如果我点击的p标签
          if(e.target == Lp[i]){                            
            bs1.scrollToElement(                            //那么就让右边滚动到对应元素
                right_.value.children[0].children[i],
                1000,
                false,
                false
            )
            activeIndex.value = i                           //设置左侧高亮
           }
        }
    } else {
        //实现效果为,点击左侧,左侧高亮项会到视口最上方
        activeIndex.value = dom.getAttribute("data-index")!             //否则直接设置高亮为当前元素
        bs1.scrollToElement(                                         //让右侧滚动到对应元素
                right_.value.children[0].children[activeIndex.value],   
                1000,                                               
                false,
                false
        )
        bs.scrollToElement(                                         //让左侧也滚动到对应元素
                left_.value.children[0].children[activeIndex.value],
                1000,
                false,
                false
        )
    }
  }
 
​
  
  
 //在组件挂载后获取dom元素
  onMounted(()=>{
    init()          //调用bs实例,用于初始化BScroll
  })
  
  
 </script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值