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>
阅读 6.1k
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>

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


如图:

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

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

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题