❤️❤️组件踩坑日记:vxe-table-select下拉表格异步加载时的数据回显问题

最近项目组有个需求,需要下拉展示一个表格,表格的数据为异步获取,然后再选中表格中的某一项。回传id和name给后端保存。保存后可编辑,但是在回显数据保存的数据时,我遇到了问题,在此简单记录一下我的解决方案。

js 复制代码
    //环境
    "vue": "^3.2.38",
    "vxe-pc-ui": "^4.8.23",
    "vxe-table": "^4.15.10"

问题复现

js 复制代码
<template>
  <div>
    <!-- <div>名称:{{ data.name }}</div> -->
    <div>id:{{ data.id }}</div>
    <vxe-table-select
      v-model="data.id"
      v-bind="vxeTableSelectProps"
      size="mini"
    ></vxe-table-select>
    <button @click="onSave">保存</button>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref } from "vue";
const data = reactive({
  name: "",
  id: "",
});

const vxeTableSelectProps = reactive({
  columns: [{ field: "label", title: "Name" }],

  gridConfig: {
    rowConfig: {
      keyField: "id",
    },
    radioConfig: {},
    loading: true,
    proxyConfig: {
      ajax: {
        query: (params) => {
          return getSelectOptions().then((res) => {
            vxeTableSelectProps.options = res;
            return res;
          });
        },
      },
    },
  },
  options: [],
  optionProps: {
    label: "label",
    value: "id",
  },
});

function onSave() {
  localStorage.setItem("userInfo", JSON.stringify(data));
}

const getSelectOptions = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const selectOptions = [
        {
          id: 10001,
          label: "哈吉蜂",
        },
        {
          id: 10002,
          label: "金露娜",
        },
        {
          id: 10003,
          label: "威龙",
        },
        {
          id: 10004,
          label: "鸟鲁鲁",
        },
      ];
      resolve(selectOptions);
      vxeTableSelectProps.gridConfig.loading = false;
    }, 1000);
  });
};

onMounted(() => {
  const saveData = JSON.parse(localStorage.getItem("userInfo") || "{}");
  data.id = saveData.id;
});
</script>

  

页面效果

可以看到当我们选中某条数据时,选择框内能正确回显我们设定的label值,这是理所当然的! 但是,当我们点击保存按钮,将数据保存到localStorage之后再刷新页面之后,界面就将会有所不同。

此时,下拉框内,回显的将是绑定的value的值,为什么会这样啦?原因是因为vxeTableSelect只有在第一次focus,弹出下拉表格时才会发请求获取数据,所以第一次进入页面时,组件并不知道id对应的label是啥。只有在请求后界面才能回显label值。网上也没发现好的解决方法。

分析了原因之后,进行了各种尝试,发现组件始终无法在第一时间拿到该展示的label值。 冥思苦想很久之后,突然有了想法:'既然组件无法自动获取到label,不妨我们帮它一把,一开始告诉它该展示啥label'

思路:初次渲染时将id改为label的值,在加载下拉选项时,赋值回本来的id

js 复制代码
<template>
...
<vxe-table-select
      v-model="data.id"
      v-bind="vxeTableSelectProps"
      size="mini"
      @change="onChange"
    ></vxe-table-select>
...    
</template> 

<script setup>
...
const originId = ref();

const onChange = ({ row }) => {
  // row为下拉表格选中的行数据
  data.name = row.label;
};
const vxeTableSelectProps = reactive({
  columns: [{ field: "label", title: "Name" }],

  gridConfig: {
    rowConfig: {
      keyField: "id",
    },
    radioConfig: {},
    loading: true,
    proxyConfig: {
      ajax: {
        query: (params) => {
          return getSelectOptions().then((res) => {
            vxeTableSelectProps.options = res;
            // 恢复数据
            data.id = originId.value;
            return res;
          });
        },
      },
    },
  },
  options: [],
  optionProps: {
    label: "label",
    value: "id",
  },
});

onMounted(() => {
  const saveData = JSON.parse(localStorage.getItem("userInfo") || "{}");
  // 先赋值成name
  originId.value = saveData.id;
  data.id = saveData.name;
  data.name = saveData.name;
});
...
</script>  

来看看效果

一开始id被我们强行改成了name,实现了数据回显

异步加载完成后,恢复id且不影响数据回显。

完整代码如下:

js 复制代码
<template>
  <div>
    <div>名称:{{ data.name }}</div>
    <div>id:{{ data.id }}</div>
    <vxe-table-select
      v-model="data.id"
      v-bind="vxeTableSelectProps"
      size="mini"
      @change="onChange"
      @focus="onFocus"
    ></vxe-table-select>
    <button @click="onSave">保存</button>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref } from "vue";
const data = reactive({
  name: "",
  id: "",
});

const vxeTableSelectProps = reactive({
  columns: [{ field: "label", title: "Name" }],

  gridConfig: {
    rowConfig: {
      keyField: "id",
    },
    radioConfig: {},
    loading: true,
    proxyConfig: {
      ajax: {
        query: (params) => {
          return getSelectOptions().then((res) => {
            vxeTableSelectProps.options = res;
            //****************************
            // 恢复数据(关键点)
            data.id = originId.value;
            //****************************
            return res;
          });
        },
      },
    },
  },
  options: [],
  optionProps: {
    label: "label",
    value: "id",
  },
});

function onSave() {
  localStorage.setItem("userInfo", JSON.stringify(data));
}

const getSelectOptions = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const selectOptions = [
        {
          id: 10001,
          label: "哈吉蜂",
        },
        {
          id: 10002,
          label: "金露娜",
        },
        {
          id: 10003,
          label: "威龙",
        },
        {
          id: 10004,
          label: "鸟鲁鲁",
        },
      ];
      resolve(selectOptions);
      vxeTableSelectProps.gridConfig.loading = false;
    }, 1000);
  });
};
const originId = ref();

const onChange = ({ row }) => {
  // row为下拉表格选中的行数据
  data.name = row.label;
};
onMounted(() => {
  const saveData = JSON.parse(localStorage.getItem("userInfo") || "{}");
  // 先赋值成name
  originId.value = saveData.id;
  data.id = saveData.name;
  data.name = saveData.name;
});
</script>

除了上述方案之外,我还尝试过将vxe-table-select的v-model绑定为data.name,此法亦能解决回显问题但是会带来新的问题------下拉列表的label可能重复,会引起组件异常,回显时无法判断应该选中哪条数据。故放弃此法。

上述方案成功解决了数据回显的需求,但是总给人一种是在邪修的感觉,有点投机取巧了,改变原始数据的方式存在一定的风险,但是管他啦,顺利完成了需求!!! Jym要是有更好的方式实现,可以分享一下,让我开开眼界😘

相关推荐
前端工作日常5 分钟前
H5 实时摄像头 + 麦克风:完整可运行 Demo 与深度拆解
前端·javascript
韩沛晓16 分钟前
uniapp跨域怎么解决
前端·javascript·uni-app
前端工作日常17 分钟前
以 Vue 项目为例串联eslint整个流程
前端·eslint
程序员鱼皮18 分钟前
太香了!我连夜给项目加上了这套 Java 监控系统
java·前端·程序员
该用户已不存在1 小时前
这几款Rust工具,开发体验直线上升
前端·后端·rust
前端雾辰1 小时前
Uniapp APP 端实现 TCP Socket 通信(ZPL 打印实战)
前端
无羡仙1 小时前
虚拟列表:怎么显示大量数据不卡
前端·react.js
云水边1 小时前
前端网络性能优化
前端
用户51681661458411 小时前
[微前端 qiankun] 加载报错:Target container with #child-container not existed while devi
前端
东北南西1 小时前
设计模式-工厂模式
前端·设计模式