Vue/vant第左右联动better-scroll效果实现(完整版)

先看完整代码: 

<template>
  <div>
    <!-- 头部 -->
    <van-sticky :offset-top="0">
      <div class="header">
        <van-icon name="chat-o" class="icon-one" />
        <van-search
          @click="search"
          placeholder="请输入搜索关键词"
          class="sousuo"
        />
        <van-icon name="scan" class="icon-two" />
      </div>
    </van-sticky>
    <!-- section部分 -->

    <section class="section" ref="sec">
      <div class="left" ref="left">
        <ul class="ulone">
          <li
            class="lione"
            v-for="(item, index) in leftList"
            :class="{ lis_one_color: index == currentIndex }"
            :key="index"
            @click="leftClick(index)"
          >
            {{ item.name }}
          </li>
        </ul>
      </div>
      <div class="right" ref="right">
        <ul class="rightulone">
          <li class="lis" v-for="(i, ind) in rightList" :key="ind">
            <div
              v-for="(item, index) in i.app_category_items"
              class="rightdiv"
              :key="index"
            >
              <div class="rightdivtwo">
                <div class="img">
                  <van-image :src="item.cover" />
                </div>
                <p>{{ item.name }}</p>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </section>
    <!-- 底部 -->
    <tabbbar></tabbbar>
  </div>
</template>

<script>
import BetterScroll from "better-scroll";
import Tabbbar from "../components/tabbbar.vue";
export default {
  name: "VantClassification",
  components: {
    Tabbbar,
  },
  data() {
    return {
      list: [],
      leftList: [],
      rightList: [],
      currentIndex: 0,
      img: [],
      rightBScroll: "",
      leftBScroll: "",
      allHeight: [], //承载右侧每一块高度值
      flag: false,
    };
  },
  created() {},
  updated() {
    if (!this.rightBScroll) {
      this.$nextTick(() => {
        this.leftBScroll = new BetterScroll(this.$refs.left, {
          click: true,
          probeType: 3,
        });
        console.log(this.leftBScroll);
        this.rightBScroll = new BetterScroll(this.$refs.right, {
          probeType: 3, // 是否会截流scroll事件
          click: true, // 是否开启点击事件
          // scrollY: true, // 是否开启Y轴滚动方向
          // useTransition: false, // 防止iphone微信滑动卡顿
          // bounce: true, // 是否启用回弹动画效果
          // momentumLimitDistance: 5, // 符合惯性拖动的最小拖动距离
        });
        // console.log(this.rightBScroll);
        let height = 0;
        this.allHeight.push(height); // 先把0放在数组的开头
        let uls = this.$refs.right.getElementsByClassName("lis");

        Array.from(uls).forEach((v) => {
          height += v.clientHeight;
          this.allHeight.push(height); // 把每个li的高度放在新数组中
          // console.log(this.allHeight);
        });
        // 右侧滚动距离
        this.rightBScroll.on("scroll", (pos) => {
          this.scrollY = Math.abs(Math.round(pos.y));
          // console.log(this.scrollY);
          for (let i = 0; i < this.allHeight.length; i++) {
            if (
              this.scrollY > this.allHeight[i] &&
              this.scrollY < this.allHeight[i + 1]
            ) {
              if (!this.flag) {
                this.currentIndex = i;
                console.log(this.currentIndex);
              }
            }
          }
        });
        // 结束时距离
        this.rightBScroll.on("scrollEnd", (pos) => {
          //结束时触发事件获取一次位置,因为使用了模式2,惯性滚动不触发事件
          this.scrollY = Math.abs(Math.round(pos.y));
          this.flag = false;
        });
      });
    }
  },
  mounted() {
    let a = this.$refs.sec;
    a.style.height = document.documentElement.clientHeight - 95 + "px";
    this.getData();
  },
  computed: {},
  methods: {
    search() {
      this.$router.push("/search");
    },
    // 请求数据
    getData() {
      this.$axios.get("/category/app_category").then((res) => {
        console.log(res);
        this.list = res.data.data;
        // console.log(this.list);
        let leftArr = [];
        let rightArr = [];
        this.list.forEach((v) => {
          leftArr.push({
            id: v.id,
            name: v.name,
          });
          rightArr.push(v);
          /* console.log(leftArr);
          console.log(rightArr); */
        });
        this.leftList = leftArr;
        // console.log(this.leftList);
        // 右侧部分
        this.rightList = rightArr;
        // console.log(this.rightList);
      });
    },
    leftClick(index) {
      // console.log(index);
      this.flag = true;
      this.currentIndex = index;
      this.rightBScroll.scrollTo(0, -this.allHeight[index], 300);
      // console.log(this.allHeight[index]);
    },
  },
};
</script>

<style  scoped>
.header {
  background-color: #fff;
  width: 100%;
  height: 45px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.icon-one {
  margin-left: 0.133333rem;
  /* width: 7%; */
}
.sousuo {
  width: 86%;
  height: 45px;
}
.icon-two {
  width: 7%;
  margin-left: 0.133333rem;
}
/* section样式 */
.section {
  margin-bottom: 50px;
  display: flex;
  overflow: hidden;
}
.ulone {
  width: 2.6667rem;
  overflow: hidden;
}
.lione {
  font-weight: bold;
  text-align: center;
  font-size: 18px;
  /* width: 100%; */
  height: 50px;
  line-height: 36px;
  margin: 10px 0;
  padding: 7px 0;
  box-sizing: border-box;
}
.lis_one_color {
  color: rgb(255, 102, 0);
  border-left: 3px rgb(255, 102, 0) solid;
}
.right {
  width: 7.3333rem;
  overflow: hidden;
}
.rightulone {
  width: 100%;
}
.rightdiv {
  width: 33%;
  /* height: 100px; */
  /* background-color: blue; */
  display: inline-block;
}
.img {
  width: 100%;
  height: 80px;
}
.rightdivtwo {
  width: 100%;
  padding: 0 5px;
  box-sizing: border-box;
  text-align: center;
}
</style>

主要绕一点的也就是中间的布局,之前是左右两边使用overflow:auto去写的

这里使用overflow:hidden

基本结构布局如下:

<section class="section" ref="sec">
      <div class="left" ref="left">
        <ul class="ulone">
          <li class="lione">
          </li>
        </ul>
      </div>
      <div class="right" ref="right">
        <ul class="rightulone">
          <li>
            <div class="rightdiv">
              <div class="rightdivtwo">
               <div class="img">
                  <van-image :src="item.cover" />
               </div>
                <p></p>
              </div>
            </div>
          </li>
        </ul>
      </div>
</section>

css样式: 

/* section样式 */
.section {
  margin-bottom: 50px;
  display: flex;
  overflow: hidden;
}
.ulone {
  width: 2.6667rem;
  overflow: hidden;
}
.lione {
  font-weight: bold;
  text-align: center;
  font-size: 18px;
  /* width: 100%; */
  height: 50px;
  line-height: 36px;
  margin: 10px 0;
  padding: 7px 0;
  box-sizing: border-box;
}
.lis_one_color {
  color: rgb(255, 102, 0);
  border-left: 3px rgb(255, 102, 0) solid;
}
.right {
  width: 7.3333rem;
  overflow: hidden;
}
.rightulone {
  width: 100%;
}
.rightdiv {
  width: 33%;
  /* height: 100px; */
  /* background-color: blue; */
  display: inline-block;
}
.img{
  width: 100%;
  height: 80px;
}
.rightdivtwo {
  width: 100%;
  padding:0 5px;
  box-sizing: border-box;
  text-align: center;
}

使用better-scroll插件让布局可以滚动

if (!this.rightBScroll) { 
 updated () {
    this.$nextTick(() => {
      this.leftBScroll = new BetterScroll(this.$refs.left, {
        click: true,
        probeType: 3,
      });
      console.log(this.leftBScroll);
      this.rightBScroll = new BetterScroll(this.$refs.right, {
        probeType: 3, // 是否会截流scroll事件
        click: true, // 是否开启点击事件
        // scrollY: true, // 是否开启Y轴滚动方向
        // useTransition: false, // 防止iphone微信滑动卡顿
        // bounce: true, // 是否启用回弹动画效果
        // momentumLimitDistance: 5, // 符合惯性拖动的最小拖动距离
      });
      console.log(this.rightBScroll);

    });
  },
}

之后获取最外层的循环的六个li

      let height = 0;
      this.allHeight.push(height);// 先把0放在数组的开头
      let uls = this.$refs.right.getElementsByClassName('lis');
      
       Array.from(uls).forEach(v => {
          height += v.clientHeight
          this.allHeight.push(height) // 把每个li的高度放在新数组中
          // console.log(this.allHeight);
        })

核心部分

    if (!this.rightBScroll) {
      this.$nextTick(() => {
        this.leftBScroll = new BetterScroll(this.$refs.left, {
          click: true,
          probeType: 3,
        });
        console.log(this.leftBScroll);
        this.rightBScroll = new BetterScroll(this.$refs.right, {
          probeType: 3, // 是否会截流scroll事件
          click: true, // 是否开启点击事件
        });
        let height = 0;
        this.allHeight.push(height); // 先把0放在数组的开头
        let uls = this.$refs.right.getElementsByClassName("lis");
        Array.from(uls).forEach((v) => {
          height += v.clientHeight;
          this.allHeight.push(height); // 把每个li的高度放在新数组中
        });
        // 右侧滚动距离
        this.rightBScroll.on("scroll", (pos) => {
          this.scrollY = Math.abs(Math.round(pos.y));
          // console.log(this.scrollY);
          for (let i = 0; i < this.allHeight.length; i++) {
            if (
              this.scrollY > this.allHeight[i] &&
              this.scrollY < this.allHeight[i + 1]
            ) {
              if (!this.flag) {
                this.currentIndex = i;
                console.log(this.currentIndex);
              }
            }
          }
        });
        // 结束滚动时距离
        this.rightBScroll.on("scrollEnd", (pos) => {
          this.scrollY = Math.abs(Math.round(pos.y));
          this.flag = false;
        });
      });
    }

 

 为什么要加一个flag的状态?如果不加状态,会出现一个小bug。左边的点击事件会随着右边的滚动事件一起进行。也就是当我点击按钮让右边滚动时,左边的列表项会从上往下依次滚动到指定位置,加了这个状态后就完美的解决了冲突问题

修改前:

 修改后:

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Southern Wind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值