刚刚解决了 Ant Design Vue 中,出现弹窗内的表单动态赋值的问题。

需求大概是这样,页面中的 Table 放置了 Key 与 Value 对应的列表。每行的右侧有个编辑按钮,点击『编辑』后弹出编辑窗口,并把该行的 Key, Value 赋值到弹窗中相对应的表单项中。

按照 Ant Design Vue 的文档写好了弹窗的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<a-modal title="Edit" :visible="visible" ...>
<a-form :form="form">
<a-form-item label="Key">
<a-input placeholder="Key name" required v-decorator="formConfig.key" />
</a-form-item>
<a-form-item label="Value">
<a-input
placeholder="Value name"
required
v-decorator="formConfig.value"
/>
</a-form-item>
</a-form>
</a-modal>

与处理逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
{
watch: {
visible(isShow) {
if (isShow) {
this.form.setFieldsValue({
["key"]: this.key,
["value"]: this.value
});
}
}
}
}

但是每次点击按钮后弹出窗口后,相对应的值并没有设置进表单中,而且控制台报了这个错:

1
Warning: You cannot set a form field before rendering a field associated with the value.

查看 DOM 树后发现,当 visible 第一次为 true 时,<a-modal> 运用单例模式被渲染为 body 的最后一个子元素。所以怀疑是在 form 还没被渲染的时候,就已经调用了 setFieldsValue 的方法。【有别于 React 版的 Ant-Design,其 Modal 提供了 forceRender 参数可供强制渲染。】

所以把方法调整为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
watch:{
visible(isShow) {
if (isShow) {
if(this.isRendered){
this.setValue(this.key, this.value);
}else{
this.isRendered = true;
setTimeout(()=>{
this.setValue(this.key, this.value);
},100);
}
}
}
}
...
methods:{
setValue(k,v){
this.form.setFieldsValue({
["key"]: k,
["value"]: v
})
}
}

这样一来,通过使用 setTimeout 的方式转化为异步赋值。其中这个 100ms 的时间差是一开始为了验证“是不是由于渲染时序的原因导致的无法赋值”的问题。验证通过后,发现去掉时间也是可以的。至于 setTimeout(fn, 0) 之所以有效,先放两篇链接。

  1. What does setTimeout with a 0ms delay do? Is this some trick to spawn a new thread, but why?
  2. Why is setTimeout(fn, 0) sometimes useful?

以上。