前言+情景复现

在前端开发中使用el-select进行选择是一个非常常用的开发手段,在一些业务逻辑中,我们通常需要用到复杂的数据类型(Object)来作为选择项。

在使用el-select使用复杂数据类型作为Option的选项

当数据回显时,如果el-option的label属性编写的不是item.label,例如:label=“item.name”

则直接对el-select所绑定的值进行赋值时会出现input框内数据为空的情况

  <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />

完整代码:

<template>
  <div id="page-box">
    <el-button @click="echo" type="primary">数据回显</el-button>
    <div>数据回显结果:{{ selectValue.data }}</div>
    <el-select
      v-model="selectValue.data"
      filterable
      class="select-input"
      remote
      reserve-keyword
      placeholder="请选择"
      :remote-method="remoteMethod"
      :loading="loading"
      style="width: 240px"
      value-key="id"
    >
      <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
    </el-select>
  </div>
</template>
<script setup lang="ts">
  const selectValue = reactive<any>({
    data: ''
  })
  const loading = ref<boolean>(false) //select选择框loading状态
  const options = ref<any>([]) //select选择框选项

  // 远程搜索数据
  const remoteMethod = (query: string) => {
    loading.value = true
    setTimeout(() => {
      loading.value = false
      options.value = [
        { id: 1, name: 'Option1', data: { name: 'Option1详情' } },
        { id: 2, name: 'Option2', data: { name: 'Option2详情' } },
        { id: 3, name: 'Option3', data: { name: 'Option3详情' } }
      ]
    }, 200)
  }
  const echo = () => {
    console.log(options.value)

    selectValue.data = { id: 4, name: '回显结果', data: { name: '回显详情' } }
    console.log(selectValue)
  }
</script>

问题发生原因:el-select源码解读

我读了一部分el-select的源码,原理在于

v-model绑定的值发生变化时,组件会尝试在当前的options列表中查找匹配的选项,

el-option使用用户传递的label选项:如:label="item.name" 作为回显内容(label),通过provide对el-select进行组件嵌套传值,el-select使用inject拿到option传递的值后绑定给input框

情景一:如果在options内存在用户直接赋值的v-model的数据,就返回该选项的回显内容

情景二:如果没有找到用户直接赋值的v-model的数据,但绑定值本身包含label属性,组件会尝试直接使用这个label

但在企业开发中,很多时候后端返回的数据并没有label属性,这时如果对数据进行回显,就会触发这种bug(特性):el-select找不到数据内的label,el-option也找不到对应的选项。input框内就会出现空字符串。

解决方案一:在回显数据内添加label属性

基于上面的情况解析,可以直接在回显的数据内添加label属性,这样即使el-option所绑定的label为不存在的值,el-selcet仍然能够回显label内容。

   <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
  // 数据回显
  const echo = () => { 
 //解决方案一:在回显数据内添加label属性
 selectValue.data = { id: 4, name: '回显结果', label: '新增的label属性提供的回显结果', data: { name: '回显详情' } }
 }

解决方案二:在el-option所绑定的option选项中添加回显数据

我们也可以直接给el-option的options选项赋值回显的数据,让el-option处理数据,并传递给el-select进行赋值。

  const echo = () => {
    // 方案二:在el-option所绑定的option选项中添加回显数据
    const echoData = { id: 4, name: '回显结果', data: { name: '回显详情' } }
    options.value.push(echoData)
    selectValue.data = echoData
  }

完整代码

<template>
  <div id="page-box">
    <el-button @click="echo" type="primary">数据回显</el-button>
    <div>数据回显结果:{{ selectValue.data }}</div>
    <el-select
      v-model="selectValue.data"
      filterable
      class="select-input"
      remote
      reserve-keyword
      placeholder="请选择"
      :remote-method="remoteMethod"
      :loading="loading"
      style="width: 240px"
      value-key="id"
    >
      <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
    </el-select>
  </div>
</template>

<script setup lang="ts">
  const selectValue = reactive<any>({
    data: ''
  })
  const loading = ref<boolean>(false) //select选择框loading状态
  const options = ref<any>([]) //select选择框选项

  // 远程搜索数据
  const remoteMethod = (query: string) => {
    loading.value = true
    setTimeout(() => {
      loading.value = false
      options.value = [
        { id: 1, name: 'Option1', data: { name: 'Option1详情' } },
        { id: 2, name: 'Option2', data: { name: 'Option2详情' } },
        { id: 3, name: 'Option3', data: { name: 'Option3详情' } }
      ]
    }, 200)
  }
  // 数据回显
  const echo = () => {
    //解决方案一:在回显数据内添加label属性
    // selectValue.data = { id: 4, name: '回显结果', label: '新增的label属性提供的回显结果', data: { name: '回显详情' } }
    // 方案二:在el-option所绑定的option选项中添加回显数据
    const echoData = { id: 4, name: '回显结果', data: { name: '回显详情' } }
    options.value.push(echoData)
    selectValue.data = echoData
  }
</script>

<style lang="scss" scoped>
  #page-box {
    width: 100%;
    height: 600px;
    display: flex;
    flex-direction: column;
    gap: 50px;
    justify-content: center;
    align-items: center;
  }
</style>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐