AntD vue select 组件错误

错误

[Vue warn]: Invalid prop: custom validator check failed for prop "value".

image.png

错误复现:https://codesandbox.io/s/vue-...

确认是官方 bug

tapd_20698031_base64_1573115689_26.png

<template>
    <a-select
        :value="selectIdList"
        placeholder="请选择讲师"
        showSearch
        :filterOption="false"
        mode="multiple"
        @search="search"
        @change="change"
    >
        <a-select-option
            v-for="{ id, name } of list"
            :id="id"
            :data-value="JSON.stringify({ userId: id, userName: name })"
            :value="id"
            :key="id"
        >
            {{ name }}
        </a-select-option>
    </a-select>
</template>

<script>

/**
 * 课程讲师下拉框
 * TODO 这个组件会导致 vue 警告,可能时 antd 的怪癖,不过不影响程序数据,可以暂且忽略
 */
export default {
    name: 'MainSpeakerSelect',
    model: {
        prop: 'value',
        event: 'change',
    },
    props: {
        /**
         * @type {MainSpeakerEntity[]}
         */
        value: {
            type: Array,
        },
    },
    data() {
        return {
            //内部使用的 List 集合
            selectIdList: [],
            //全部的 List 选项
            list: [],
        }
    },
    created() {
        this.search('')
    },
    watch: {
        value(val) {
            this.selectIdList = (val || []).map(({ userId }) => userId)
        },
    },
    methods: {
        async search() {
            this.list = [
                { id: 1, name: '用户 谭磊', organization: 'aR5DPA', phone: '@phone' },
                { id: 2, name: '用户 高静', organization: 'WAh', phone: '@phone' },
                { id: 3, name: '用户 廖艳', organization: '9jvb', phone: '@phone' },
                { id: 4, name: '用户 张娟', organization: '(TX8', phone: '@phone' },
                {id: 5, name: '用户 夏秀英', organization: 'rk#MsL5', phone: '@phone',},
                { id: 6, name: '用户 戴桂英', organization: '#ke6aX', phone: '@phone' },
                { id: 7, name: '用户 范平', organization: 'n7dp', phone: '@phone' },
                { id: 8, name: '用户 常霞', organization: 'AF0GP', phone: '@phone' },
                { id: 9, name: '用户 常艳', organization: 'ou1AQ', phone: '@phone' },
                { id: 10, name: '用户 方勇', organization: 'k7u0', phone: '@phone' },
            ]
        },
        change(selectIdList) {
            const value = selectIdList.map(
                id => JSON.parse(document.getElementById(id).dataset.value),
            )
            this.$emit('change', value)
        },
    },
}
</script>
阅读 698
评论
    3 个回答

    去掉labelInValue

      临时解决方案,绑定对象到 data-* 上,然后在改变的时候去从 DOM 中查找并反序列化回来

      <template>
          <a-select
              :value="selectIdList"
              placeholder="请选择讲师"
              showSearch
              :filterOption="false"
              mode="multiple"
              @search="search"
              @change="change"
          >
              <a-select-option
                  v-for="{ id, name } of list"
                  :id="id"
                  :data-value="JSON.stringify({ userId: id, userName: name })"
                  :value="id"
                  :key="id"
              >
                  {{ name }}
              </a-select-option>
          </a-select>
      </template>
      
      <script>
      
      /**
       * 课程讲师下拉框
       * TODO 这个组件会导致 vue 警告,可能时 antd 的怪癖,不过不影响程序数据,可以暂且忽略
       */
      export default {
          name: 'MainSpeakerSelect',
          model: {
              prop: 'value',
              event: 'change',
          },
          props: {
              /**
               * @type {MainSpeakerEntity[]}
               */
              value: {
                  type: Array,
              },
          },
          data() {
              return {
                  //内部使用的 List 集合
                  selectIdList: [],
                  //全部的 List 选项
                  list: [],
              }
          },
          created() {
              this.search('')
          },
          watch: {
              value(val) {
                  this.selectIdList = (val || []).map(({ userId }) => userId)
              },
          },
          methods: {
              async search() {
                  this.list = [
                      { id: 1, name: '用户 谭磊', organization: 'aR5DPA', phone: '@phone' },
                      { id: 2, name: '用户 高静', organization: 'WAh', phone: '@phone' },
                      { id: 3, name: '用户 廖艳', organization: '9jvb', phone: '@phone' },
                      { id: 4, name: '用户 张娟', organization: '(TX8', phone: '@phone' },
                      {id: 5, name: '用户 夏秀英', organization: 'rk#MsL5', phone: '@phone',},
                      { id: 6, name: '用户 戴桂英', organization: '#ke6aX', phone: '@phone' },
                      { id: 7, name: '用户 范平', organization: 'n7dp', phone: '@phone' },
                      { id: 8, name: '用户 常霞', organization: 'AF0GP', phone: '@phone' },
                      { id: 9, name: '用户 常艳', organization: 'ou1AQ', phone: '@phone' },
                      { id: 10, name: '用户 方勇', organization: 'k7u0', phone: '@phone' },
                  ]
              },
              change(selectIdList) {
                  const value = selectIdList.map(
                      id => JSON.parse(document.getElementById(id).dataset.value),
                  )
                  this.$emit('change', value)
              },
          },
      }
      </script>
        • 109

        问题在于重复赋值,重复选中,所以select的验证过不了,正常情况下,同一选项一次选中下一次就应该是取消


        如图:

        clipboard.png
        对于你的组件,我的理解是,你想要在选择变化的时候拿到多选框中的值,那么1,2两者选择一个就可以了
        1是vue双向绑定,所以在select发生变化时,selectList也会得到对应的赋值(会触发value=> selectList= value),此时两者的值是相同的
        2是你自定义事件,里面也给selectList进行了赋值,虽然说赋值前后selectList的值内容没有变化,但是指针变化了,vue判断出来prop更新了,于是触发了validator,这个验证函数我并没有看,猜测其中有一个判断是,已经选择的条目不能重复选择,已经取消的条目不能重复取消

        解决方案:
        1和2保留一个,个人比较倾向于defaultValue+onChange的组合

          撰写回答

          登录后参与交流、获取后续更新提醒