Skip to content

Vue.js ElementUI 切换下拉框控件显示时显示了错误的文字

🏷️ Vue.js ElementUI

页面共有三个下拉框,后面两个根据第一个下拉框的值来切换显示,具体代码如下:

xml
<template>
  <el-dialog :title="isEdit ? '编辑': '新增'" width="45%"
          :visible.sync="visible" :before-close="close" label-position="right"
          :modal-append-to-body="false"
          :close-on-press-escape="false"
          :close-on-click-modal="false">
    <el-form ref="ent" :model="ent" :rules="rules" label-width="120px">
      <el-form-item label="类型" prop="type">
        <el-select v-model="ent.type" placeholder="请选择" style="width: 100%">
          <el-option :key="1" label="链接" :value="1" />
          <el-option :key="2" label="应用" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="ent.type == 1" label="链接" prop="link">
        <el-select v-model="ent.link" placeholder="请选择链接" :disabled="ent.type != 1" style="width: 100%">
          <el-option :key="1" label="链接1" :value="1" />
          <el-option :key="2" label="链接2" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="ent.type == 2" label="应用" prop="appletIds">
        <el-select v-model="ent.appletIds" multiple clearable placeholder="请选择应用" :disabled="ent.type != 2" style="width: 100%">
          <el-option :key="1" label="应用1" :value="1" />
          <el-option :key="2" label="应用2" :value="2" />
        </el-select>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>

类型选择为 链接 后,链接下拉框显示,选择 链接 1

之后切换类型为 应用 ,此时应用的下拉框值应该为空,但是却显示为 链接 1

此时控件的 value 值为 链接 1

之后尝试了如下几种方法:

  • 调整控件位置
    切换第二个和第三个下拉框时仍然还是有这个问题。只有将第三个下拉框调整到第一个下拉框之前时,才能正常显示。
  • 改变第一个下拉框选项的同时,重置其它两个下拉框的值
    不能正常显示。
  • 删除第三个下拉框的 multiple 属性
    可以正常显示,但是这个不符合需求。
  • 在第三个下拉框前面加一个 display: none 的下拉框
    可以正常显示,就是代码有点丑陋。

最后在同事的帮助下,才发现对这两个控件分别指定一个 key 就可以了。

代码如下:

xml
<template>
  <el-dialog :title="isEdit ? '编辑': '新增'" width="45%"
          :visible.sync="visible" :before-close="close" label-position="right"
          :modal-append-to-body="false"
          :close-on-press-escape="false"
          :close-on-click-modal="false">
    <el-form ref="ent" :model="ent" :rules="rules" label-width="120px">
      <el-form-item label="类型" prop="type">
        <el-select v-model="ent.type" placeholder="请选择" style="width: 100%">
          <el-option :key="1" label="链接" :value="1" />
          <el-option :key="2" label="应用" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="ent.type == 1" label="链接" prop="link">
        <el-select key="link" v-model="ent.link" placeholder="请选择链接" :disabled="ent.type != 1" style="width: 100%">
          <el-option :key="1" label="链接1" :value="1" />
          <el-option :key="2" label="链接2" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="ent.type == 2" label="应用" prop="appletIds">
        <el-select key="appletIds" v-model="ent.appletIds" multiple clearable placeholder="请选择应用" :disabled="ent.type != 2" style="width: 100%">
          <el-option :key="1" label="应用1" :value="1" />
          <el-option :key="2" label="应用2" :value="2" />
        </el-select>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>

那么这个 key 属性是用来做什么的呢?

下面的说明摘自官方文档

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

xml
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

自己动手试一试,在输入框中输入一些文本,然后按下切换按钮:

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可:

xml
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

现在,每次切换时,输入框都将被重新渲染。请看:

注意,<label> 元素仍然会被高效地复用,因为它们没有添加 key attribute

上面的说明完美的解释了遇到的问题,这一切都是元素复用导致的。

个人觉得这仍然是 ElementUI 的一个 bug,毕竟这两个下拉框跟官方文档中的场景并不完全一样,都是绑定了属性的,应该保证页面的展示和绑定的属性值一致。