«

better-scroll(vue2)

yang 发布于 阅读:310 Vue2阶段


1.1 什么是better-scroll?

BetterScroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件,使用纯 JavaScript 实现的,这意味着它是无依赖的。

中文文档:https://better-scroll.github.io/docs/zh-CN/

1.2 安装插件核心

yarn add @better-scroll/core

1.3 使用插件

//引入插件
import BetterScroll from '@better-scroll/core';

//实例化插件
let scroll = new BetterScroll('.wrapper');

注意:只能有一个子元素,才能进行滚动

1.4 滚动插件的坑

第一个:去掉垂直的滚动条,去掉overflow-y:scroll; ,更换成超出隐藏 overflow:hidden;

第二个:滚动插件初始化的位置,必须放在请求数据的后面,并且使用定时器或 $nextTick 回调函数进行初始化

第三个:better-scroll只能滚动条一个子元素,第一个子元素的高度必须超出父容器

1.5 左联右(点击左边分类,右边滚动到指定的商品模块)

实现原理:点击左边商品分类,获取下标,与右边的商品列表进行一一对应

第一步:点击商品分类,获取下标

//前提条件:让滚动元素可以点击
this.bs1 = new BetterScroll('.aside', {
  probeType: 3,
  click: true, //让滚动元素可以点击
});

//点击商品分类的函数
clickCate(i){
  console.log(i);
}

第二步:给商品列表标题设置有规律的id

<h3 class="list-title" :id="'title'+i">{{v.name}}</h3>

第三步:滚动到指定的标签

this.bs2.scrollToElement('#title'+i, 500);

1.6 右联左(滚动右边的商品列表,左边的商品分类跟着变化)

核心思想:计算出每一个标题的位置,通过滚动事件获取当前位置,再遍历位置数组,判断当前位置在哪个区间,得到对应的下标,就可以设置左边激活下标,并跳过去。

//计算所有商品标题的位置
let arr = this.list.map((v,i)=>{
  return document.querySelector('#title'+i).offsetTop -  document.querySelector('#title0').offsetTop;
});

//滚动右边商品列表时
this.bs2.on('scroll', pos=>{
  let y = Math.abs(pos.y);

  for(let i=0; i<arr.length-1; i++){
    if( y>=arr[i] && y<arr[i+1] ){ //判断当前滚动值在哪个位置区间,设置左边分类项
      this.activeKey = i;
      this.bs1.scrollToElement('#cate'+i, 300);
    }
  }
});

扩展阅读: 百度搜索 “js clientWidth offsetWidth scrollWidth”

具体代码体现如下:

<template>
  <div class="goods">
    <!-- 左边商品分类 -->
    <aside class="aside">
      <van-sidebar v-model="activeKey">
        <van-sidebar-item
          v-for="(v, i) in cate"
          :title="v"
          :key="i"
          @click="show(i)"
          :id="'cate' + i"
        />
        <!-- 占位符 -->
        <div class="aside_place"></div>
      </van-sidebar>
    </aside>

    <!-- 右边商品列表 -->
    <div class="list">
      <ul>
        <li v-for="(v, i) in list" :key="i" :id="v.name">
          <h3 class="list-title" :id="'title' + i">{{ v.name }}</h3>
          <van-card
            v-for="(v2, i2) in v.foods"
            :key="i2"
            :price="v2.price | decimalFix"
            :desc="v2.goodsDesc"
            :title="v2.name"
            :thumb="v2.imgUrl"
            @click="detail(v2)"
          >
            <template #tags>
              <van-tag plain round type="warning">特惠</van-tag>
            </template>
            <template #footer>
              <van-stepper
                v-model="v2.cartNum"
                theme="round"
                button-size="22"
                disable-input
                :min="0"
                :max="100"
                v-on:click.native.stop
                @change="changeCart"
              />
            </template>
          </van-card>
        </li>
        <!-- 占位符 -->
        <div class="place"></div>
      </ul>
    </div>

    <!-- 购物车 -->
    <shop-cart></shop-cart>
  </div>
</template>
<script>
import { goodsList } from "@/api/goods.js";
//引入插件
import BetterScroll from "@better-scroll/core";

export default {
  components: {
    ShopCart: () => import("@/components/ShopCart.vue"),
  },

  data() {
    return {
      activeKey: 0,
      bs1: null, //左边商品分类滚动实例
      bs2: null, //右边商品列表滚动实例
    };
  },

  async created() {
    //判断当前vuex中有没有数据,如果没有就发请求,有就不发
    if (this.list.length === 0) {
      let res = await goodsList();

      // console.log(res);

      // 给每一个商品加入一个新的购物数量元素
      res.data.data.forEach((v) => {
        v.foods.forEach((v2) => {
          v2.cartNum = 0;
          // console.log(v2);
        });
      });

      // 将读到的数据存到vuex中
      this.$store.commit("addGoods", res.data.data);
      // console.log(this.list);
    }

    // 初始化better - scroll;
    this.$nextTick(() => {
      //左边商品分类滚动实例
      this.bs1 = new BetterScroll(".aside", {
        probeType: 3,
        click: true, //让滚动的元素可以被点击
      });

      //右边商品列表滚动实例
      this.bs2 = new BetterScroll(".list", {
        probeType: 3,
        click: true,
      });

      //计算所有商品标题的位置
      let arr = this.list.map((v, i) => {
        return (
          // 减去最上方到右边第一个标题的距离
          document.querySelector("#title" + i).offsetTop -
          document.querySelector("#title0").offsetTop
        );
      });
      // console.log(arr);

      //滚动右边商品列表时
      this.bs2.on("scroll", (pos) => {
        let y = Math.abs(pos.y);
        // console.log(y);

        // 根据每个标题高度循环遍历来实现标题与左边的联动
        for (let i = 0; i < arr.length - 1; i++) {
          if (y >= arr[i] && y < arr[i + 1]) {
            this.activeKey = i;

            // 实现跟左边标题的滑动效果
            this.bs1.scrollToElement("#cate" + i, 300);
          }
        }
      });
    });
  },

  methods: {
    //点击商品分类实现右边列表的联动 函数(scrollToElement)
    show(i) {
      // console.log(i);
      this.bs2.scrollToElement("#title" + i, 500);
    },

    // 点击+ -时计算购物车商品实现联动
    changeCart() {
      this.$store.commit("addCart");
    },

    // 点击商品时跳转到详情页
    detail(row) {
      this.$router.push("/detail?id=" + row.id);
    },
  },

  computed: {
    //从vuex里面读取出来的商品列表
    list() {
      return this.$store.state.goodsList;
    },

    //商品分类数据
    cate() {
      return this.$store.state.goodsList.map((v) => v.name);
    },
  },
};
</script>
<style lang="scss" scoped>
// 隐藏所有的滚动条
::-webkit-scrollbar {
  display: none;
  // Chrome Safari
}
.goods {
  display: flex;
  height: 100%;
  overflow-y: scroll;

  // 左边商品分类
  .aside {
    width: 30%;
    background: #f7f8fa;
    overflow: hidden;

    .van-sidebar {
      width: 100%;
    }

    .van-sidebar-item--select::before {
      background-color: #f60;
    }

    // 占位符
    .aside_place {
      height: 85px;
    }
  }
  // 右边
  .list {
    width: 1px;
    flex-grow: 1;
    // overflow-y: auto;
    overflow: hidden;

    .list-title {
      line-height: 32px;
      background: #f4f4f4;
      border-left: 2px solid #ccc;
      font-size: 16px;
      color: #666;
      text-indent: 10px;
    }

    .van-card {
      width: 100%;
      padding: 6px;
    }
    .van-card__price {
      color: #f00;
    }

    // 占位符
    .place {
      height: 85px;
    }
  }
}
</style>

版权所有:微4e
文章标题:better-scroll(vue2)
除非注明,文章均为 微4e 原创,请勿用于任何商业用途,禁止转载

推荐阅读:


扫描二维码,在手机上阅读
请先 登录 再评论