两级联动组件使用(vue)开箱即用

349 阅读1分钟

两级联动组件使用(vue)🎈🎈🎈🎈

代码片段复制时 需要安装less预处理器 样式使用的是less

效果展示

Snipaste_2022-05-02_03-22-33.png

Snipaste_2022-05-02_03-23-12.png

Snipaste_2022-05-02_03-23-18.png

代码片段

<template>
  <div class="nextLevel">
    <h2 class="nextLevel_h2">点击展示下一级</h2>
    <div class="nextLevel_box">
      <ul class="nextLevel_box_1">
        <li
          :class="{ activate: activateId === i.id }"
          v-for="i in arr"
          :key="i.id"
          @click="addFn(i)"
        >
          <div
            class="button"
            :class="{ activate_btn: i.checked }"
            @click.stop="btnFn(i)"
          ></div>
          商品分类:{{ i.name }}
        </li>
      </ul>
      <ul class="nextLevel_box_2" v-show="arr2.length">
        <li v-for="i in arr2" :key="i.id">
          <div
            class="button"
            @click.stop="btnFn2(i)"
            :class="{ activate_btn: i.checked }"
          ></div>
          商品/名称:{{ i.name }}
        </li>
      </ul>
    </div>
  </div>
</template>
<style lang="less" scoped>
@bacColor: aqua;
ul,
li,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
  cursor: pointer;
}
li:hover {
  background-color: @bacColor;
}
.nextLevel {
  margin: 10% auto;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  &_h2 {
    color: red;
  }
  &_box {
    width: 50%;
    display: flex;
    & > ul {
      flex: 1;
      background-color: pink;
      li {
        padding-left: 15px;
        display: flex;
        align-items: center;
        &.activate {
          background-color: @bacColor;
        }
        .button {
          width: 16px;
          height: 16px;
          border: 1px solid #000;
          border-radius: 50%;
          margin-right: 5px;
          margin-top: 2px;
          // 激活按钮样式
          &.activate_btn {
            position: relative;
            &::before {
              position: absolute;
              content: "✔"; //伪元素必须得要有 content属性
              line-height: 90%;
              text-align: center;
              color: #fff;
              border-radius: 50%;
              left: 50%;
              top: 50%;
              transform: translateX(-50%) translateY(-50%);
              background-color: royalblue;
            }
          }
        }
      }
    }
    & > ul:nth-child(2) {
      background-color: @bacColor;
    }
  }
}
</style>
<script>
export default {
  name: "nextLevel",
  data() {
    return {
      // 数据定义
      arr: [
        {
          id: "0",
          name: "水果",
          children: [
            {
              id: "01",
              name: "苹果",
            },
            {
              id: "02",
              name: "香蕉",
            },
          ],
          checked: false,
        },
        {
          id: "1",
          name: "蔬菜",
          children: [
            {
              id: "11",
              name: "油麦菜",
            },
            {
              id: "12",
              name: "菠菜",
            },
            {
              id: "13",
              name: "花菜",
            },
            {
              id: "14",
              name: "白菜",
            },
            {
              id: "15",
              name: "红萝卜",
            },
          ],
          checked: false,
        },
        {
          id: "2",
          name: "刀具",
          checked: false,
        },
      ],
      arr2: [], // 二级指标展示
      activateId: "0", // 默认展示哪一级
      arrVal: [], //请求id集合数据
      echoObj: { //回显数据
        level1: ['0','1'],
        level2: [],
      },
    };
  },
  methods: {
    // 展开下一级
    addFn(i) {
      this.activateId = i.id;
      // 追加数据
      if (Array.isArray(i.children)) {
        this.arr2 = [...i.children];
      } else {
        this.arr2.length = 0;
        this.activateId = "";
      }
    },
    // 一级激活
    btnFn(i) {
      this.arr = this.btnMapFn(this.arr, i.id, !i.checked);
      const obj = this.arr.find((e) => e.id === i.id);
      this.addFn(obj);
    },
    // 二级激活
    btnFn2(i) {
      this.arr2 = this.btnMapFn(this.arr2, i.id, !i.checked);
      let bl = this.arr2.every((e) => e.checked);
      this.arr = this.btnMapFn(this.arr, i.id.substring(0, 1), bl, this.arr2);
    },
    // 获取值
    getValFn() {
      let arr2 = [];
      let arr1 = this.arr
        .map((e) => {
          let valArr =
            e?.children?.filter((e) => e.checked).map((e) => e.id) || [];
          arr2 = [...arr2, ...valArr];
          if (e.checked) {
            return e.id;
          }
        })
        .filter((e) => e);
      this.arrVal = [...arr1, ...arr2];
      this.echoObj.level1 = [...arr1];
      this.echoObj.level2 = [...arr2];
      // console.log(this.arrVal); 获取值
    },
    // 一级+二级点击map进行包装
    btnMapFn(arr, id1, checked1, children1) {
      return arr.map((e) => {
        if (e.id === id1) {
          return {
            ...e,
            checked: checked1 ?? e.checked,
            children:
              children1 ||
              e?.children?.map((v) => ({ ...v, checked: checked1 })), // 右边逻辑是一级处理
          };
        } else {
          return {
            ...e,
          };
        }
      });
    },
  },
  mounted() {
    const { level1, level2 } = this.echoObj;
    // 一级回显 + 二级回显
    this.arr = this.arr.map((e) => {
      const bl1 = Boolean(level1.filter((v) => v === e.id)[0]);
      if (bl1) { //一级联动二级
        return {
          ...e,
          checked: bl1,
          children: e?.children?.map((v) => {
            return {
              ...v,
              checked: bl1,
            };
          }),
        };
      } else { //二级联动一级
        // 映射出相对应的数据
        const arrFilter = e?.children?.map((v) => (Boolean(level2.filter((i) => i === v.id)[0])))
        //全部为true 则一级高亮
        const bl2 = arrFilter?.findIndex(v => v === false) === -1 
        return {
          ...e,
          checked: bl2,
          children: e?.children?.map((v,i) => {
            return {
              ...v,
              checked: arrFilter[i],
            };
          }),
        };
      }
    });
    // 默认展开一项指标
    this.addFn(this.arr.find((e) => e.id === this.activateId));
  },
  watch: {
    arr: {
      deep: true,
      handler() {
        this.getValFn();
      },
    },
  },
};
</script>

各位同行如果有更好的实现方案 评论一起交流加技术讨论 互相学习

动动发财的小手点赞加收藏💕💕💕💕