JS antdv实现表格树形级联效果

概述

项目中需实现以下这种效果:级联数据,表格横向排列,数据之间相互联动。现有UI组件无法满足此需求,只能撸起袖子加油干!!
在这里插入图片描述
实现效果如下
请添加图片描述
开发前先准备一个树形数据 treeData.js

const treeData = [
  {
    areaName: "江苏",
    areaCode: "100",
    checked: false,
    indeterminate: false,
    order: 1,
    children: [
      {
        areaName: "无锡",
        areaCode: "1001",
        parentCode: "100",
        checked: false,
        indeterminate: false,
        order: 1,
        children: [
          {
            areaName: "鼓楼区",
            areaCode: "10011",
            parentCode: "1001",
            checked: false,
            indeterminate: false,
            order: 1,
            children: [],
          },
          {
            areaName: "玄武区",
            areaCode: "10012",
            parentCode: "1001",
            checked: false,
            indeterminate: false,
            order: 2,
            children: [],
          },
          {
            areaName: "秦港区",
            areaCode: "10013",
            parentCode: "1001",
            checked: false,
            indeterminate: false,
            order: 3,
            children: [],
          },
          {
            areaName: "浦口区",
            areaCode: "10014",
            parentCode: "1001",
            checked: false,
            indeterminate: false,
            order: 4,
            children: [],
          },
        ],
      },
      {
        areaName: "南京",
        areaCode: "1002",
        parentCode: "100",
        checked: false,
        indeterminate: false,
        order: 1,
        children: [
          {
            areaName: "鼓楼区2",
            areaCode: "10021",
            parentCode: "1002",
            checked: false,
            indeterminate: false,
            order: 1,
            children: [],
          },
          {
            areaName: "玄武区2",
            areaCode: "10022",
            parentCode: "1002",
            checked: false,
            indeterminate: false,
            order: 2,
            children: [],
          },
          {
            areaName: "秦港区2",
            areaCode: "10023",
            parentCode: "1002",
            checked: false,
            indeterminate: false,
            order: 3,
            children: [],
          },
          {
            areaName: "浦口区2",
            areaCode: "10024",
            parentCode: "1002",
            checked: false,
            indeterminate: false,
            order: 4,
            children: [],
          },
        ],
      },
    ],
  },
  {
    areaName: "浙江",
    areaCode: "200",
    checked: false,
    indeterminate: false,
    order: 1,
    children: [
      {
        areaName: "杭州",
        areaCode: "2001",
        parentCode: "200",
        checked: false,
        indeterminate: false,
        order: 1,
        children: [
          {
            areaName: "鼓楼区1",
            areaCode: "20011",
            parentCode: "2001",
            checked: false,
            indeterminate: false,
            order: 1,
            children: [],
          },
          {
            areaName: "玄武区1",
            areaCode: "20012",
            parentCode: "2001",
            checked: false,
            indeterminate: false,
            order: 2,
            children: [],
          },
          {
            areaName: "秦港区1",
            areaCode: "20013",
            parentCode: "2001",
            checked: false,
            indeterminate: false,
            order: 3,
            children: [],
          },
          {
            areaName: "浦口区1",
            areaCode: "20014",
            parentCode: "2001",
            checked: false,
            indeterminate: false,
            order: 4,
            children: [],
          },
        ],
      },
      {
        areaName: "宁波",
        areaCode: "2002",
        parentCode: "200",
        checked: false,
        indeterminate: false,
        order: 1,
        children: [
          {
            areaName: "鼓楼区2",
            areaCode: "20021",
            parentCode: "2002",
            checked: false,
            indeterminate: false,
            order: 1,
            children: [],
          },
          {
            areaName: "玄武区2",
            areaCode: "20022",
            parentCode: "2002",
            checked: false,
            indeterminate: false,
            order: 2,
            children: [],
          },
          {
            areaName: "秦港区2",
            areaCode: "20023",
            parentCode: "2002",
            checked: false,
            indeterminate: false,
            order: 3,
            children: [],
          },
          {
            areaName: "浦口区2",
            areaCode: "20024",
            parentCode: "2002",
            checked: false,
            indeterminate: false,
            order: 4,
            children: [],
          },
        ],
      },
    ],
  },
];
export default treeData;

完整代码
具体的每一个细节我都在代码注释了,这里就不单独抽出来赘述了,详细的分析请看大屏幕…

<template>
  <a-modal
    :title="addConfig.title"
    :showSubmit="false"
    :visible="addConfig.visible"
    @ok="handleAddOk"
    @cancel="handleCancel"
  >
    <div class="container_box">
      <div class="container_header">
        <div v-for="item in 3" :key="item" class="header_item">
          <div class="title"><span>名称</span></div>
          <div class="title"><span>排序</span></div>
        </div>
      </div>
      <div class="container_body">
        <div class="body_item" v-for="(list, index) in listData" :key="index">
          <div
            class="item_list"
            :style="{
              backgroundColor: item.clickStatus
                ? 'rgba(19,194,194,.3)'
                : '#ffffff',
            }"
            v-for="item in list"
            :key="item.areaCode"
            @click.capture="handleClickAreaItem(item)"
          >
            <div class="item">
              <a-checkbox
                :indeterminate="item.indeterminate"
                v-model="item.checked"
                @change="onCheckAllChange($event, item)"
              >
                {{ item.areaName }}
              </a-checkbox>
            </div>
            <div class="item">
              <a-input v-model="item.order" placeholder="排序" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </a-modal>
</template>

<script>
import treeData from "./treeData";
let filterData = [];
export default {
  name: "addArea",
  props: {
    addConfig: Object,
  },
  data() {
    return {
      listData: [],
    };
  },
  mounted() {
    this.handleTreeData(treeData, 1);
    // 初始化数据
    treeData[0].clickStatus = true;
    treeData[0].children[0].clickStatus = true;
    this.listData = [
      treeData,
      treeData[0].children,
      treeData[0].children[0].children,
    ];
  },
  methods: {
    // 点击每一个item 显示选中状态并进行数据联动
    handleClickAreaItem(item) {
      if (item.level === 3) return;
      let list = [];
      if (item.parentCode) {
        // 点击第二或第三级
        this.handleFilterData(treeData, item.parentCode);
        list = filterData[0]?.children;
      } else {
        // 点击第一级
        list = treeData;
        // 切换第一级时 第二级默认选择第一个
        let arr = treeData.filter((lis) => lis.areaCode === item.areaCode);
        arr[0]?.children.forEach((lis, index) => {
          if (index === 0) {
            lis.clickStatus = true;
          } else {
            lis.clickStatus = false;
          }
        });
      }
      list.forEach((lis) => {
        if (lis.areaCode === item.areaCode) {
          lis.clickStatus = true;
          // 子级数据跟随联动
          if (item.level === 1) {
            this.listData[1] = lis.children;
            this.listData[2] = lis.children[0].children;
          } else if (item.level === 2) {
            this.listData[2] = lis.children;
          }
        } else {
          lis.clickStatus = false;
        }
      });
    },
    handleTreeData(list, levelIndex) {
      list.forEach((lis) => {
        lis.clickStatus = false;
        // 动态标记每层层级
        lis.level = levelIndex;
        if (lis.children && lis.children.length !== 0)
          this.handleTreeData(lis.children, levelIndex + 1);
      });
    },
    handleAddOk(e) {
      e && e.preventDefault();
    },
    handleCancel() {
      this.$emit("cancel");
    },
    // 向下处理树形选中/未选中
    handleDownTreeCheck(arr, checked) {
      arr.forEach((iii) => {
        iii.indeterminate = false;
        iii.checked = checked;
        if (iii.children && iii.children.length !== 0)
          this.handleDownTreeCheck(iii.children, checked);
      });
    },
    // 向上处理树形选中/未选中
    handleUpTreeCheck(item) {
      this.handleFilterData(treeData, item.parentCode);
      let list = filterData[0];
      let status1 = list.children.some((ii) => ii.checked);
      let status2 = list.children.every((ii) => ii.checked);
      let statusIn = list.children.some((ii) => ii.indeterminate);
      // 当不全选中且子集有勾选中 或者 子集有indeterminate状态为true
      list.indeterminate = status1 || statusIn;
      // 当全选中的时候 indeterminate 状态 为false
      if (status2) list.indeterminate = false;
      list.checked = status2;
      // 层层向上处理
      if (list.parentCode) this.handleUpTreeCheck(list);
    },
    onCheckAllChange(e, item) {
      item.indeterminate = false;
      filterData = [];
      // 当前点击的该项中有父级的情况下 比如当前点击项为第二、三....
      if (item.parentCode) this.handleFilterData(treeData, item.parentCode);
      // 当前点击的该项中存在父级数据情况下 比如当前点击项为第二、三.... 则向上处理元素状态
      if (filterData.length > 0) this.handleUpTreeCheck(item);
      // 当前点击的该项中存在子集数据情况下 则向下处理元素状态
      if (item.children && item.children.length > 0)
        this.handleDownTreeCheck(item.children, e.target.checked);
    },
    handleFilterData(list, parentCode) {
      // 过滤数据
      list.forEach((lis) => {
        if (lis.areaCode === parentCode) {
          filterData = [];
          filterData.push(lis);
        }
        if (lis.children && lis.children.length !== 0)
          this.handleFilterData(lis.children, parentCode);
      });
    },
  },
};
</script>

<style lang="less" scoped>
/deep/.ant-modal {
  width: 840px !important;
  .ant-modal-close {
    color: #fff;
    .ant-modal-close-x {
      height: 47px;
      line-height: 47px;
    }
  }
  .ant-modal-header {
    padding: 12px 20px;
    background-color: #02c7b5;
    .ant-modal-title {
      font-size: 16px;
      font-weight: 500;
      color: #ffffff;
    }
  }
  .ant-modal-body {
    // padding: 24px 27px 6px;
  }
  .container_box {
    width: 100%;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    .container_header {
      display: flex;
      align-items: center;
      width: 100%;
      background-color: #f4f7fb !important;
      border-radius: 6px 6px 0px 0px;
      .header_item {
        flex: 4;
        height: 42px;
        line-height: 42px;
        display: flex;
        align-items: center;
        .title {
          flex: 6;
          text-align: center;
          font-size: 14px;
          font-weight: 400;
          color: #242525;
        }
      }
    }
    .container_body {
      display: flex;
      width: 100%;
      .body_item {
        flex: 4;
        flex-direction: column;
        .item_list {
          display: flex;
          align-items: center;
          margin-top: 10px;
          .item {
            flex: 6;
            text-align: center;
            font-size: 14px;
            font-weight: 400;
            color: #242525;
            .ant-input {
              width: 86px !important;
            }
          }
        }
        &:nth-child(2) {
          border-left: 2px solid #f1f1f1;
          border-right: 2px solid #f1f1f1;
        }
      }
    }
  }
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值