vueComponent / ant-design-vue

🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜
https://antdv.com/
Other
20.07k stars 3.78k forks source link

a-input 组件不受控 #7720

Open guaijie opened 2 months ago

guaijie commented 2 months ago

Version

undefined

Environment

vue: 3.x ; ant-design-vue: 4.2.3

Reproduction link

Edit on CodeSandbox

a-input 组件不受控

<template>
  <h1>{{ msg }}</h1>
  <a-input v-model:value="msg" @input="handleChange" />
  <!-- 非受控组件 -->
  <a-input :value="1" />
  <!-- 受控组件 -->
  <a-select style="width: 100%" :value="1" :options="options" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
const msg = ref();
const options = [
  { label: 1, value: 1 },
  { label: 2, value: 2 },
];
const handleChange = () => {
  msg.value = "Hello";
};
</script>

What is expected?

期待 a-input 组件与 a-select 组件一样,都是受控组件

What is actually happening?

no response

pangao66 commented 2 months ago

input的输入触发事件是 @input事件 跟html原生保持一致, @change 是失焦的时候触发的

guaijie commented 2 months ago

input的输入触发事件是 @input事件 跟html原生保持一致, @change 是失焦的时候触发的

那你改成 input 事件再尝试,我强调的是 a-input 组件不受控,而不在于用哪个事件去主动修改值

jack-7788 commented 1 month ago

首先你为什么会有如此奇怪的想法, v-model:value , 是由 :value + @update:value 组成的语法糖, 你想 使用 const handleChange = () => msg.value = 'Hello' 生效, 那么就不用使用 v-model ,应该这么写 <a-input :value="msg" @update:value ="handleChange " />

cc-hearts commented 1 month ago

作者的意思应该是

<a-input :value="msg" /> 

如果 msg 为 hello world 的话,说明组件是受控的(意思由 value 控制组件的值), 由于没有进行 msg的值变更操作。 因此预期的情况是无论在输入框中输入任何内容,值始终是hello world

如有误,请指正

guaijie commented 1 month ago

首先你为什么会有如此奇怪的想法, v-model:value , 是由 :value + @update:value 组成的语法糖, 你想 使用 const handleChange = () => msg.value = 'Hello' 生效, 那么就不用使用 v-model ,应该这么写 <a-input :value="msg" @update:value ="handleChange " />

那你就拆成以下这种写法再去尝试嘛,所有的事件都控制不了输入框的显示值,。

<template>
  <h1>{{ msg }}</h1>
  <a-input :value="msg" @update:value="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
1;
const msg = ref();
const handleChange = () => {
  msg.value = "Hello";
};
</script>

不管你是用 update:value 还是 change 还是 input 你首先得清楚这些事件的触发时机吧。 image

guaijie commented 1 month ago

作者的意思应该是

<a-input :value="msg" /> 

如果 msg 为 hello world 的话,说明组件是受控的(意思由 value 控制组件的值), 由于没有进行 msg的值变更操作。 因此预期的情况是无论在输入框中输入任何内容,值始终是hello world

如有误,请指正

像你所描述的:’组件完全受控‘,这样当然是最好的。但 vue 官方并未提及受控组件的概念,不像 react 。因此组件受控需要交给组件库去实现。所以我并不清楚提出质疑的那位同志是否了解过这一概念。

我也不说这组件能完全受控,但现在是任何一个事件居然都控制不了输入框的值,直接导致我无法控制字符类型、长度等 事实上,我更期望的就是你所描述的,所有表单组件皆为受控组件,但这要看库的维护者是否有意愿这么改

jack-7788 commented 1 month ago

首先你为什么会有如此奇怪的想法, v-model:value , 是由 :value + @update:value 组成的语法糖, 你想 使用 const handleChange = () => msg.value = 'Hello' 生效, 那么就不用使用 v-model ,应该这么写 <a-input :value="msg" @update:value ="handleChange " />

那你就拆成以下这种写法再去尝试嘛,所有的事件都控制不了输入框的显示值,。

<template>
  <h1>{{ msg }}</h1>
  <a-input :value="msg" @update:value="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
1;
const msg = ref();
const handleChange = () => {
  msg.value = "Hello";
};
</script>

不管你是用 update:value 还是 change 还是 input 你首先得清楚这些事件的触发时机吧。 image

第一 , msg.value = 'Hello'; 肯定你键盘怎么敲始终都是 Hello 呀,因为只有这里在赋值呀

第二, 如果你想拿到你想输入的值 , 不管是update:value 事件,还是chang事件,还是input事件, 他都有回调参数的,

<template>
  <h1>{{ msg }}</h1>
  <a-input :value="msg" @update:value="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
1;
const msg = ref();
const handleChange = (value) => {
//value 是回调参数的值 , 你可以根据此参数进行逻辑判断,在进行下一行的赋值逻辑
  msg.value = "xxx";
};
</script>
guaijie commented 1 month ago

首先你为什么会有如此奇怪的想法, v-model:value , 是由 :value + @update:value 组成的语法糖, 你想 使用 const handleChange = () => msg.value = 'Hello' 生效, 那么就不用使用 v-model ,应该这么写 <a-input :value="msg" @update:value ="handleChange " />

那你就拆成以下这种写法再去尝试嘛,所有的事件都控制不了输入框的显示值,。

<template>
  <h1>{{ msg }}</h1>
  <a-input :value="msg" @update:value="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
1;
const msg = ref();
const handleChange = () => {
  msg.value = "Hello";
};
</script>

不管你是用 update:value 还是 change 还是 input 你首先得清楚这些事件的触发时机吧。 image

第一 , msg.value = 'Hello'; 肯定你键盘怎么敲始终都是 Hello 呀,因为只有这里在赋值呀

第二, 如果你想拿到你想输入的值 , 不管是update:value 事件,还是chang事件,还是input事件, 他都有回调参数的,

<template>
  <h1>{{ msg }}</h1>
  <a-input :value="msg" @update:value="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";
1;
const msg = ref();
const handleChange = (value) => {
//value 是回调参数的值 , 你可以根据此参数进行逻辑判断,在进行下一行的赋值逻辑
  msg.value = "xxx";
};
</script>

你到底有没有明白别人提这个 issue 的意思,你能不能自己先去理解别人的意思和先尝试再来表达自己的看法。 怕有人误解,特地重新改了 demo。首先你先去 demo 里尝试,看看这个 a-input 是否满足你所说的第一条 要是你还不理解就认真去看 cc-hearts 这位参与者的评论

你第一个评论明显是没理解各个事件的触发时机, 以下代码第一种,第二种有什么区别,我通过 input 事件把值重新改成 'Hello' 有什么问题吗?此时的输入框难道不应该总是显示 'Hello'?然而实际情况是这样的吗?

<template>
  <h1>{{ msg }}</h1>
  <!-- 第一种 -->
  <a-input :value="msg" @update:value="handleChange" />
  <!-- 第二种 -->
  <a-input v-model:value="msg" @input="handleChange" />
</template>
<script lang="ts" setup>
import { ref } from "vue";

const msg = ref();
const handleChange = () => {
  msg.value = "Hello";
};
</script>
23431 commented 1 month ago

今天也遇到这个问题了,试了下 elemnt-plus是正常的

JonathanLiuc commented 1 month ago

问题是有,具体原因可以看一下原生input dom的value逻辑,然后看下作者在setValue之后nextTick中回调的逻辑就能看出原因了,作者用的那个$forceUpdate应该是最终比对了属性一样没更新原生input的dom,临时解法是在自己的update:value事件触发时补一个nextTick,回调里通过外层ref取到input的dom节点,如果dom的value与传入给a-input的value不同,就赋值input的dom的value为外面的传入给a-input的value