vue实现左右联动面板

该代码示例展示了如何在Vue中创建一个左右联动的面板,适用于处理二级分类数据,如外卖小程序中的分类导航。左侧面板显示一级分类,点击后右侧面板滚动展示对应二级分类的内容。通过`@click`和`@scroll`事件监听用户交互,实现平滑滚动效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue实现左右联动面板

一般适用于分类二级数组、外卖小程序
<template>
  <div>
    <div class="nmc-content">
      <div class="nmc-wrapper">
        <div
          class="left"
          ref="scrollLeft"
        >
          <div
            v-for="(item, index) in arr"
            :key="index"
            ref='leftBox'
            @click="changeModel(index)"
            :class="[current==index?'active flex-one':'common flex-one']"
          >
            {{item.name}}
          </div>
        </div>

        <div
          class="right"
          ref="scroll"
          @scroll="handleScroll"
        >
          <div
            class="main-content"
            v-for="(item, index) in arr"
            :key="index"
          >
            <div
              class="top-title"
              ref="rightTit"
            >{{item.name}}</div>
            <div class="bottom-content">
              <ul
                class="bottom-ul"
                v-if="item.list"
              >
                <li
                  class="bottom-item"
                  v-for="(item1, index1) in item.list"
                  :key="index1"
                >

                  <img
                    src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F202103%2F09%2F20210309094501_jfyix.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1675911945&t=14dcf3ffd9b9884f4accc0941ed6f140"
                    alt=""
                  />

                </li>
              </ul>

            </div>

          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      leftClickFlag: false,
      arr: [
        {
          name: "分类1",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类2",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类3",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类4",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类5",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类6",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类7",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类8",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类9",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类10",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
        {
          name: "分类11",
          list: [
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
            { name: "二级" },
          ],
        },
      ],
      current: 0,
      listHeight: [],
      scrollY: 0,
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.getBoxHeight();
      this.current = 0;
      this.changeModel(0);
    });
  },
  methods: {
    getBoxHeight() {
      setTimeout(() => {
        //延时计算元素的宽度
        let rightItems =
          this.$refs.scroll.getElementsByClassName("main-content"); //获取指定类名的所有元素
        let height = 0;
        this.listHeight.push(height);
        for (let i = 0; i < rightItems.length; i++) {
          let item = rightItems[i]; // 右边的每一个模块(蓝色标题 + 标题下面所带的内容)
          height += item.clientHeight;
          this.listHeight.push(height); // 把右边模块内容的高度全都放到一个数组中
        }
        this.arr.forEach((item, index) => {
          // 把上面弄的那些高度分别放入总数据中,方便点击左边让右边滚动到所对应的模块
          this.$set(item, "distance", this.listHeight[index]);
        });
      }, 1000); //增加延时,等图片渲染完毕后进行计算
    },
    changeModel(index) {
      if (index == 0) {
        this.$refs.scroll.scrollTop = 0;
      } else {
        this.$refs.scroll.scrollTop = this.arr[index].distance;
      }
      this.current = index;
      this.leftClickFlag = true;
    },
    // 左侧滚动
    handleScrollLeft() {
      let leftHeight = this.$refs.leftBox[0].clientHeight;
      let height = (this.current - 6) * leftHeight;
      if (this.current > 6) {
        this.$refs.scrollTop += height;
      }

      if (this.current <= 6) {
        this.$refs.scrollTop = 0;
      }
    },
    // 滚动时触发
    handleScroll() {
      this.scrollY = this.$refs.scroll.scrollTop; // 先获取滚动元素的scrollTop,主要用它来进行判断
      if (this.scrollY < this.arr[1].distance) {
        this.current = 0;
      } else {
        for (let i = 0; i < this.listHeight.length; i++) {
          let start = this.listHeight[i + 1]; // 右边模块内容的高度
          let end = this.listHeight[i + 2]; // 右边模块内容的高度 加上 右边模块标题的高度
          if (this.scrollY >= start && this.scrollY < end) {
            if (this.leftClickFlag == false) {
              //如果右侧数据过少,不触发右侧滚动
              this.current = i + 1;
            }
            if (this.leftClickFlag) {
              //设置完之后立马重置,右侧滚动触发左侧
              this.leftClickFlag = false;
            }

            this.handleScrollLeft();
            return;
          }
        }
      }
    },
  },
};
</script>

<style lang='scss' scoped>
.flex-one {
  display: flex;
  justify-content: center;
  align-content: center;
}
.nmc-content {
  background: #f4f5f6;
  padding: 0.6rem 0 0 0;
  .nmc-wrapper {
    width: 100%;
    height: calc(100vh - 0.6rem);
    display: flex;
    .left {
      width: 4.5rem;
      // height: 100%;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      color: #333333;

      &::-webkit-scrollbar {
        display: none; /* Chrome Safari */
      }
      > div {
        font-size: 0.7rem;
        font-weight: 500;
        width: 4.5rem;
        height: 2.5rem;
        position: relative;

        .top {
          position: absolute;
          top: -0.5rem;
          right: 0;
          width: 0.5rem;
          height: 0.5rem;
          background: white;
        }
        .bottom {
          position: absolute;
          top: 2.5rem;
          right: 0;
          width: 0.5rem;
          height: 0.5rem;
          background: white;
        }
      }
      .active {
        background: #ffffff;
        background: white;
        color: #333333;
        display: flex;
        align-items: center;
        border-radius: 0;
        .line {
          width: 0.15rem;
          height: 0.75rem;
          object-fit: cover;
          margin: 0 0.5rem 0 0;
        }
      }
      .common {
        color: #666666;
        line-height: 2.5rem;
      }
    }

    .right {
      background: white;
      position: relative;
      flex: 1;
      width: 100%;
      height: 100%;
      background: #fff;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      padding: 0.5rem;

      .main-content {
        position: relative;
        width: 100%;
        .top-title {
          height: 2rem;

          text-align: left;
          line-height: 2rem;
          font-size: 0.65rem;
          font-weight: 500;
          color: #333333;
        }
        .bottom-content {
          // display: flex;
          // flex-wrap: wrap;
          // min-height: 17rem;
          // margin: 0 0.5rem;
          .bottom-ul {
            width: 100%;
            display: flex;
            flex-wrap: wrap;
            .bottom-item {
              width: 33.33%;
              // height: 5rem;
              display: flex;
              flex-direction: column;
              align-items: center;
              margin: 0 0 0.5rem 0;
              position: relative;
              > img:first-child {
                width: 2.5rem;
                height: 2.5rem;
                // border: 0.025rem solid #f2f2f2;
                border-radius: 0.25rem;
                object-fit: cover;
                box-shadow: 0rem 0.08rem 0.15rem 0.08rem
                  rgba(194, 146, 108, 0.1);
              }
            }
          }
        }
      }
    }
  }
}
</style>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值