h5使用better scroll实现左右列表联动

安装vant^2.12.38和better-scroll^2.5.1

javascript 复制代码
<template>
  <div>
    <div class="dept-filter" @click="showFilter">
      <div class="name">{{ params.name }}</div>
      <img class="img" src="@/assets/images/index/filter.png" />
    </div>
    <van-popup v-model="show" position="bottom" :style="{ height: '70vh' }">
      <div class="title-box">
        <div class="title">店铺列表</div>
        <img class="close" src="@/assets/images/index/close.png" @click="show = false" />
      </div>
      <div class="content-box">
        <div class="left">
          <div
            @click="setDept(item, index)"
            class="item"
            :class="currentDeptIndex === index ? 'active' : ''"
            v-for="(item, index) in list"
            :key="item.deptId"
          >
            <div class="line"></div>
            <div class="dept">{{ item.deptName }}</div>
          </div>
        </div>
        <div class="right" @mousewheel="dataScroll" @touchmove="dataScroll">
          <div
            class="item right-item"
            v-for="(item, index) in list"
            :key="item.deptId"
            :ref="'id' + item.deptId"
          >
            <div class="dept weight">{{ item.deptName }}</div>
            <div class="store" :ref="'dept' + item.deptId" @click="setAllStore(item, index)">
              <div
                class="name"
                :class="params.deptId === item.deptId && params.storeId === null ? 'active' : ''"
              >
                所有店铺
              </div>
              <img
                v-if="params.deptId === item.deptId && params.storeId === null"
                class="checked"
                src="@/assets/images/index/checked.png"
              />
              <!-- 占位 -->
              <div v-else class="checked"></div>
            </div>
            <div class="dept" v-if="item.storeList.length !== 0">
              部门下店铺({{ item.storeList.length }})
            </div>
            <div
              class="store"
              @click="setStore(item, child, index)"
              v-for="child in item.storeList"
              :key="child.storeId"
              :ref="'dept' + item.deptId + child.storeId"
            >
              <div class="name" :class="params.storeId === child.storeId ? 'active' : ''">
                {{ child.storeName }}
              </div>
              <img
                v-if="params.storeId === child.storeId"
                class="checked"
                src="@/assets/images/index/checked.png"
              />
              <div v-else class="checked"></div>
            </div>
          </div>
        </div>
      </div>
    </van-popup>
  </div>
</template>
<script>
export default {
  name: 'DeptFilter1',
  data() {
    return {
      show: false,
      params: {
        deptId: 1,
        storeId: null,
        name: '所有部门'
      },
      currentDeptIndex: 0,
      list: [
        {
          deptId: 1,
          deptName: '所有部门',
          storeList: []
        },
        {
          deptId: 2,
          deptName: '软件研发部',
          storeList: []
        },
        {
          deptId: 3,
          deptName: '事业部',
          storeList: [
            { storeId: 1, storeName: '大药房官方旗舰店' },
            { storeId: 2, storeName: '拼多多事业店-拼多多事业店' },
            { storeId: 3, storeName: '拼多多事业店-拼多多事业店' }
          ]
        },
        {
          deptId: 4,
          deptName: '技术部',
          storeList: [
            { storeId: 13, storeName: '大药房官方旗舰店' },
            { storeId: 4, storeName: '拼多多事业店-拼多多事业店' },
            {
              storeId: 5,
              storeName:
                '拼多多事业部拼多多拼多多事业部拼多多拼多多事业部拼多多拼多多事业部拼多多拼多多事业部拼多多'
            },
            { storeId: 6, storeName: '拼多多事业店-拼多多事业店' },
            { storeId: 7, storeName: '拼多多事业店-拼多多事业店' },
            { storeId: 8, storeName: '拼多多事业店-拼多多事业店' },
            { storeId: 9, storeName: '拼多多事业店-拼多多事业店' },
            { storeId: 10, storeName: '拼多多事业店-拼多多事业店' }
          ]
        },
        {
          deptId: 5,
          deptName: '人事部',
          storeList: [
            { storeId: 11, storeName: '大药房官方旗舰店' },
            { storeId: 12, storeName: '拼多多事业店-拼多多事业店' }
          ]
        }
      ],
      initTop: 0
    }
  },
  methods: {
    setDept(item, index) {
      this.currentDeptIndex = index
      this.$refs['id' + item.deptId][0].scrollIntoView({ behavior: 'smooth' })
    },
    setAllStore(item, index) {
      this.params.deptId = item.deptId
      this.params.storeId = null
      this.params.name = item.deptName
      this.currentDeptIndex = index
      this.show = false
      console.log(this.params)
      this.$emit('getParams', this.params)
    },
    setStore(item, child, index) {
      this.params.storeId = child.storeId
      this.params.deptId = item.deptId
      this.params.name = child.storeName
      this.currentDeptIndex = index
      this.show = false
      console.log(this.params)
      this.$emit('getParams', this.params)
    },
    showFilter() {
      this.show = true
      this.setInitTop()
      this.topTop()
    },
    //设置选中元素置顶
    topTop() {
      this.$nextTick(() => {
        let ref = 'dept' + this.params.deptId
        if (this.params.storeId !== null) {
          ref = 'dept' + this.params.deptId + this.params.storeId
        }
        this.$refs[ref][0].scrollIntoView({ behavior: 'smooth' })
      })
    },
    //获取初始高度
    setInitTop() {
      this.$nextTick(() => {
        setTimeout(() => {
          const element = document.getElementsByClassName('title-box')[0]
          this.initTop = element.getBoundingClientRect().top + element.clientHeight
        }, 400)
      })
    },
    dataScroll() {
      const element = document.getElementsByClassName('right-item')
      this.currentDeptIndex = 0
      for (let i = 0; i < element.length; i++) {
        if (element[i].getBoundingClientRect().top <= this.initTop) {
          this.currentDeptIndex = i
        }
      }
    }
  }
}
</script>

<style scoped lang="scss">
.dept-filter {
  display: flex;
  align-items: center;
  background: #191e28;
  color: #fff;
  height: 30px;
  .name {
    font-weight: 500;
    font-size: 13px;
    line-height: 13px;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    margin: 0 5px 0 10px;
    max-width: 92px;
  }
  .img {
    width: 12px;
    height: 12px;
  }
}
::v-deep .van-popup {
  border-radius: 10px 10px 0 0;
  background: linear-gradient(
    179.71deg,
    rgba(23, 28, 37, 1) 0.75%,
    rgba(49, 55, 65, 1) 49.55%,
    rgba(23, 28, 37, 1) 98.76%
  );
  overflow-y: hidden;
  color: #ffffff;
}
.title-box {
  font-weight: 600;
  font-size: 15px;
  padding: 16px 20px;
  position: relative;
  .title {
    text-align: center;
  }
  .close {
    width: 30px;
    height: 30px;
    position: absolute;
    right: 20px;
    top: 12px;
  }
}
.content-box {
  display: flex;
  .left {
    width: 108px;
    height: calc(70vh - 52px);
    overflow-y: scroll;
    .item {
      height: 48px;
      display: flex;
      align-items: center;
      .line {
        width: 4px;
        height: 16px;
      }
      .dept {
        padding: 0 12px 0 8px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        font-size: 14px;
      }
    }
    .active {
      .dept {
        background: linear-gradient(
          136.52deg,
          rgba(4, 189, 248, 0.88) 4.9%,
          rgba(8, 252, 223, 0.88) 132.73%
        );
        -webkit-background-clip: text !important;
        -webkit-text-fill-color: transparent;
      }
      .line {
        background: linear-gradient(
          136.52deg,
          rgba(4, 189, 248, 0.88) 4.9%,
          rgba(8, 252, 223, 0.88) 132.73%
        );
      }
    }
  }

  .right {
    width: calc(100vw - 108px);
    height: calc(70vh - 52px);
    overflow-y: scroll;
    .item {
      border-top: 2px solid rgba(255, 255, 255, 0.5);
      padding: 0 16px 0 16px;
      &:first-child {
        border: none;
      }
      .dept {
        color: #bfbfbf;
        font-size: 12px;
        height: 25px;
        display: flex;
        align-items: flex-end;
      }
      .weight {
        font-weight: 500;
      }
      .store {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 12px 0;
        font-size: 14px;
        .name {
          width: calc(100vw - 170px);
        }
        .active {
          background: linear-gradient(
            136.52deg,
            rgba(4, 189, 248, 0.88) 4.9%,
            rgba(8, 252, 223, 0.88) 132.73%
          );
          -webkit-background-clip: text !important;
          -webkit-text-fill-color: transparent;
        }
        .checked {
          width: 20px;
          height: 20px;
          margin-left: 10px;
        }
      }
    }
  }
}
</style>

展示效果

相关推荐
雨 子34 分钟前
Spring Web MVC
前端·spring boot·spring·mvc·postman
计算机毕设指导642 分钟前
基于Springboot美食推荐商城系统【附源码】
java·前端·spring boot·后端·spring·tomcat·美食
!win !1 小时前
外部H5唤起常用小程序链接规则整理
前端·小程序
染指悲剧1 小时前
vue实现虚拟列表滚动
前端·javascript·vue.js
林涧泣1 小时前
【Uniapp-Vue3】navigator路由与页面跳转
前端·vue.js·uni-app
浩浩测试一下2 小时前
Web渗透测试之XSS跨站脚本之JS输出 以及 什么是闭合标签 一篇文章给你说明白
前端·javascript·安全·web安全·网络安全·html·系统安全
一棵开花的树,枝芽无限靠近你3 小时前
【PPTist】插入形状、插入图片、插入图表
前端·笔记·学习·编辑器·ppt·pptist
不会玩技术的技术girl3 小时前
获取淘宝商品详情高级版 API 接口 Java 示例代码
java·开发语言·前端
金州饿霸3 小时前
hadoop-yarn常用命令
大数据·前端·hadoop
前端搬运工X3 小时前
Object.keys 的原生 JS 类型之困
javascript·typescript