element Cascader级联选择器数据多时卡顿问题记录并解决

2023-12-13 04:43:23

一、问题

最近项目遇到一个问题,如下图:当选择“所属单位”时,测试的电脑总出现卡顿并退出现象,但神奇的是我和其他人的电脑点击是正常的。这可怎么办呢,头皮发麻

在这里插入图片描述

问题描述
在这里插入图片描述

后面多试了几次,发现我的电脑也卡住了。但并没有像测试那样卡死,时卡时不卡。于是,我打开了“任务管理器”,果然,Google Chrome的CPU迅速标黄(测试的电脑直接爆红的哈哈)
在这里插入图片描述

二、解决方案

后来经过百度和查阅资料,明白了这是因为后端是一次性返回的数据太多,导致联级选择器嵌套了dom且绑定相关事件,从而存在卡死现象。

2.1、方案一:Cascader级联选择器动态加载方式(不推荐,数据多仍会卡死)

我看官网上有个动态加载,即根据上级的数据点击再加载下一层数据。但可能是因为本次数据太多的原因,测试电脑仍处于卡死状态(注:测试电脑是8G,数据多更容易卡)。动态加载的代码当时忘记保存,在这里我也不过多赘述,小伙伴可以根据官网的案例进行尝试一下。
在这里插入图片描述

2.2 方案二:根据前一级动态加载后一级

前一级选择后若后一级有数据则显示下拉框(这里下拉框不能写固定:子公司后面可能还有子公司!!!)
在这里插入图片描述

由于“所属单位”所在的地方比较多,所以在这里我就对该功能封装了一下,具体代码如下:

<template>
  <div class="company">
    <custom-select
      v-for="(item, index) in companyList"
      :key="index"
      v-model="searchForm[index].company"
      style="width: 33.3%"
      :options="companyList[index]"
      placeholder="请选择"
      :defaultProps="defaultProps"
      @selectChange="
        getCompanyList(searchForm[index].company, Number(index) + 1, true, true)
      "
    />
  </div>
</template>
<script>
// CustomSelect是对element中的select进行封装了的组件
import CustomSelect from "@/components/customComponents/CustomSelect";

export default {
  components: {
    CustomSelect
  },
  props: {
    orgIds: {
      type: String,
      default: ""
    },
    isCompile: {
      type: Boolean,
      default: false
    },
    //重置时清空
    isClear: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      defaultProps: {
        value: "id",
        label: "orgName",
        key: "id"
      },
      searchForm: [
        {
          company: ""
        }
      ],
      companyList: [[]],
      lastData: [], //上次数据
      onoff: false 
    };
  },
  watch: {
    isClear: {
      handler(val) {
        if (val) {
          let searchArr = this.searchForm.toSpliced(0, 1, {
            company: ""
          });
          this.searchForm = searchArr.slice(0, 1);
          this.companyList = this.companyList.slice(0, 1);
        }
      },
      immediate: true
    },
    orgIds: {
      async handler(val) {
        if (val && this.isCompile && !this.onoff) {
          this.onoff = true;
          this.searchForm = [];
          const orgIds = this.orgIds.split(",");

          for (let i = 0; i < orgIds.length; i++) {
            this.searchForm.push({
              company: orgIds[i]
            });
            await this.getCompanyList(orgIds[i], i + 1, true);
          }
        }
      },
      immediate: true
    }
  },
  async mounted() {
    await this.getCompanyList("", 0, false);
  },

  methods: {
    async getCompanyList(id, index, isEmit, isClick) {
      const { data } = await this.$api.expertManagement.getDeptList({
        companyType: "",
        orgType: "0",
        pid: id || "1"
      });
      if (data.length) {
        if (index < this.companyList.length && isEmit) {
          //当点击之前的索引&选择情况
          let arr = this.companyList.toSpliced(index, 1, data);
          let searchArr = this.searchForm.toSpliced(index, 1, {
            company: ""
          });
          this.searchForm = searchArr.slice(0, index + 1);
          this.companyList = arr.slice(0, index + 1);
        } else if (index == this.companyList.length && isEmit) {
          //点击当前的索引&选择情况
          if (isClick) {
            this.searchForm.push({
              company: ""
            });
          }

          this.$nextTick(() => {
            this.companyList.push([]);
            this.companyList[index].push(...data);
          });
        } else if (!isEmit) {
          //第一次加载
          this.companyList[index].push(...data);
        }
      }
      let searchForm = this.searchForm?.map(item => {
        return item.company;
      });
      let currentId = "";
      for (let i = this.searchForm.length - 1; i >= 0; i--) {
        if (this.searchForm[i].company) {
          currentId = this.searchForm[i].company;
          break;
        }
      }

      if (isEmit && isClick) {
        this.$emit("selectChange", searchForm?.join(","), currentId);
      }
    }
  }
};
</script>
<style lang="scss" scoped>
.company {
  width: 100%;
}
</style>

上面代码比较多,功能比较复杂,主要要考虑的有

  • 控制选择后没有子公司数据了应不添加下拉选择框
  • 当返回点击之前的(即上级)公司不添加下拉选择框,并将后一级的数据清空
  • 回显时搜索和装数据的索引需要对应等等。

三、总结

方案二更多的用到了数组的方法,所以数组方法一定要牢记,注意双向绑定!当然,若小伙伴有其他更好的解决方案,也欢迎留言

文章来源:https://blog.csdn.net/weixin_45532665/article/details/134953441
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。