ant design vue Modal 对话框和表单的使用
https://www.antdv.com/components/modal-cn/
对话框基本使用
<template>
<div>
<a-button type="primary" @click="showModal">
显示模态框
</a-button>
<a-modal
title="模态框标题"
:visible="visible"
:confirm-loading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
>
<p>{{ ModalText }}</p>
</a-modal>
</div>
</template>
<script>
export default {
data() {
return {
ModalText: 'Content of the modal',
visible: false,
confirmLoading: false,
};
},
methods: {
//显示模态框
showModal() {
this.visible = true;
},
//点击ok
handleOk(e) {
this.ModalText = 'The modal will be closed after two seconds';
this.confirmLoading = true;
setTimeout(() => {
this.visible = false;
this.confirmLoading = false;
}, 2000);
},
//点击cancel
handleCancel(e) {
console.log('Clicked cancel button');
this.visible = false;
},
},
};
</script>
效果
设置对话框确认和取消按钮的文字
ok-text : 设置确认按钮文字
cancel-text : 设置取消按钮文字
例:
<a-modal
title="模态框标题"
ok-text="确认"
cancel-text="取消"
:visible="visible"
:confirm-loading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
>
效果
对话框结合form表单使用
https://www.antdv.com/components/form-cn/#components-form-demo-form-in-modal-to-create
方式1:自定义组件模板的方式
<template>
<div>
<a-button type="primary" @click="showModal">
显示模态框
</a-button>
<collection-create-form
ref="collectionForm"
:visible="visible"
@cancel="handleCancel"
@create="handleCreate"
/>
</div>
</template>
<script>
const CollectionCreateForm = {
props: ['visible'],
beforeCreate() {
this.form = this.$form.createForm(this, { name: 'form_in_modal' });
},
template: `
<a-modal
:visible="visible"
title='模态框标题'
okText='确认'
cancel-text="取消"
@cancel="() => { $emit('cancel') }"
@ok="() => { $emit('create') }"
>
<a-form layout='vertical' :form="form">
<a-form-item label='Title'>
<a-input
v-decorator="[
'title',
{
rules: [{ required: true, message: 'title必填!' }],
}
]"
/>
</a-form-item>
<a-form-item label='Description'>
<a-input
type='textarea'
v-decorator="['description']"
/>
</a-form-item>
<a-form-item class='collection-create-form_last-form-item'>
<a-radio-group
v-decorator="[
'modifier',
{
initialValue: 'private',
}
]"
>
<a-radio value='public'>Public</a-radio>
<a-radio value='private'>Private</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</a-modal>
`,
};
export default {
components: { CollectionCreateForm },
data() {
return {
visible: false,
};
},
methods: {
//显示模态框
showModal() {
this.visible = true;
},
//关闭模态框
handleCancel() {
this.visible = false;
},
//点击确认
handleCreate() {
const form = this.$refs.collectionForm.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('form 表单内容: ', values);
form.resetFields();
this.visible = false;
});
},
},
};
</script>
效果
注意:这种方式需要支持template选项
报错参考:https://www.cnblogs.com/makalochen/p/13994493.html
方式二:组件绑定form
<template>
<div>
<!--添加按钮和模态框-->
<a-button type="primary" @click="showModal">
添加
</a-button>
<a-modal
:visible="visible"
:title= "modelTitle"
okText='确认'
cancel-text="取消"
@cancel="handleCancel"
@ok="handleOk"
>
<!--表单 并将表单的值绑定到this.from-->
<a-form layout='vertical' :form="form">
<!--每一项元素-->
<a-form-item label='用户名'>
<a-input
v-decorator="[
'username',
{
rules: [{ required: true, message: '请填写登录用户名!' }],
}
]"
/>
</a-form-item>
<a-form-item label='密码'>
<a-input
type='password'
v-decorator="[
'password',
{
rules: [{ required: true, message: '请填写登录密码!' }],
}
]"
/>
</a-form-item>
<a-form-item label="状态">
<a-radio-group
v-decorator="[
'status',
{
initialValue: '1',
}
]"
>
<a-radio value='1'>启用</a-radio>
<a-radio value='0'>禁用</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
//el 创建前
beforeCreate() {
//创建表单
this.form = this.$form.createForm(this, { name: 'form_in_modal' });
},
data() {
return {
visible: false,
//模态对话框标题
modelTitle: '模态框标题',
};
},
methods: {
//显示模态框
showModal() {
this.visible = true;
},
//关闭模态框
handleCancel() {
this.visible = false;
},
//点击确认
handleOk() {
const form = this.form;
form.validateFields((err, values) => {
if (err) {
return;
}
console.log('form 表单内容: ', values);
form.resetFields();
this.visible = false;
});
},
},
};
</script>
效果
设置 确认按钮提交的loading
例:
组件设置
<!--对话框-->
<a-modal
:visible="visible"
:title= "modelTitle"
:confirm-loading="confirmLoading"
okText='确认'
cancel-text="取消"
@cancel="handleCancel"
@ok="add"
>
data() 设置
//true表示loading,反之则使用false
confirmLoading: false,
设置model的表单项
//设置模态框的form表单的值
this.$nextTick(()=>{
setTimeout(() => {
this.form.setFieldsValue({
username : record.username,
password : record.password,
status : record.status
});
})
})
设置表单项报错的问题
Warning: You cannot set a form field before rendering a field associated with the value.
https://www.cnblogs.com/cirry/p/12483131.html
在用ant-design-vue的框架中,使用到了这种场景,就是点击编辑按钮,弹出modal模态框,渲染modal模态框中的form表单页面,并给表单赋值,但是在给表单赋值的时候,总是会报错。
错误提示: Warning: You cannot set a form field before rendering a field associated with the value.
经过一番查找后发现,造成这种原因一般有以下几个原因:
1.使用了表单的方法setFieldsValue(),来设置一组输入控件的值,传入的值为object,但是传入的值要和表单的值一一对应,能少传不能多传。
遇到这种情况的解决方式为:form渲染需要什么值你就传什么值
方式1:一个一个传
this.form.setFieldsValue({ note: '123', mark: '456' })
方式2:
add (record) { //record:需要引用的值
this.visible = true
this.mdl = Object.assign({}, record) // 浅拷贝
this.form.setFieldsValue(pick(this.mdl, 'note', 'mark')) // loadsh的pick方法
}
但是你会发现这么些还是报同样的错误。按照错误提示的原意:不能在表单渲染之前赋值
2.调用setFieldsValue()方法,需要放在$nextTick()函数中执行,改为如下即可:
this.$nextTick(()=>{
this.form.setFieldsValue(pick(this.mdl, 'note', 'mark')) // loadsh的pick方法
})
一般到这里就能解决问题了,如果还在报同样的错误,那就这样吧:
3.再放到setTimeout()方法中
this.$nextTick(() => {
setTimeout(() => {
this.form.setFieldsValue(pick(this.mdl, 'note', 'mark')) // loadsh的pick方法
})
})
关于form表单使用v-decorator绑定了默认值不能修改的问题
this.form.getFieldDecorator(id, options) 和 v-decorator="[id, options]" #
经过
getFieldDecorator
或v-decorator
包装的控件,表单控件会自动添加value
(或valuePropName
指定的其他属性)onChange
(或trigger
指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
- 你不再需要也不应该用
onChange
来做同步,但还是可以继续监听onChange
等事件。- 你不能用控件的
value
defaultValue
等属性来设置表单域的值,默认值可以用getFieldDecorator
或v-decorator
里的initialValue
。- 你不应该用
v-model
,可以使用this.form.setFieldsValue
来动态改变表单值。
使用form表单是不能修改的,推荐使用FormModel表单,而且v2版本也移除了form表单,保留了formModel表单:
https://2x.antdv.com/docs/vue/migration-v2-cn/
组件重构 #
在 1.x 中我们提供了 Form、FormModel 两个表单组件,原有的 Form 组件使用 v-decorator 进行数据绑定,在 Vue2 中我们通过上下文进行强制更新组件,但是在 Vue3 中,由于引入 patchFlag 等优化方式,强制刷新会破坏 patchFlag 带来的性能优势。所以在 2.0 版本中我们将 Form、FormModel 进行合并,保留了 FormModel 的使用方式,丰富了相关功能,并改名成 Form。
FormModel表单使用
FormModel表单: https://www.antdv.com/components/form-model-cn/
基本使用:
<template>
<a-form-model :model="form" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-model-item label="Activity name">
<a-input v-model="form.name" />
</a-form-model-item>
<a-form-model-item label="Activity zone">
<a-select v-model="form.region" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="Activity time">
<a-date-picker
v-model="form.date1"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-model-item>
<a-form-model-item label="Instant delivery">
<a-switch v-model="form.delivery" />
</a-form-model-item>
<a-form-model-item label="Activity type">
<a-checkbox-group v-model="form.type">
<a-checkbox value="1" name="type">
Online
</a-checkbox>
<a-checkbox value="2" name="type">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="Resources">
<a-radio-group v-model="form.resource">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="Activity form">
<a-input v-model="form.desc" type="textarea" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="onSubmit">
Create
</a-button>
<a-button style="margin-left: 10px;">
Cancel
</a-button>
</a-form-model-item>
</a-form-model>
</template>
<script>
export default {
data() {
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
form: {
name: '',
region: undefined,
date1: undefined,
delivery: false,
type: [],
resource: '',
desc: '',
},
};
},
methods: {
onSubmit() {
console.log('submit!', this.form);
},
},
};
</script>
效果
注意:双向绑定切换需要使用字符串的形式,就算是数值也需要,
如:
status : '1'
this.form.status = ''+record.status;
表单验证 #
Form 组件提供了表单验证的功能,只需要通过 rules
属性传入约定的验证规则,并将 FormItem
的 prop
属性设置为需校验的字段名即可。校验规则参见 async-validator
<template>
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-model-item ref="name" label="Activity name" prop="name">
<a-input
v-model="form.name"
@blur="
() => {
$refs.name.onFieldBlur();
}
"
/>
</a-form-model-item>
<a-form-model-item label="Activity zone" prop="region">
<a-select v-model="form.region" placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="Activity time" required prop="date1">
<a-date-picker
v-model="form.date1"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;"
/>
</a-form-model-item>
<a-form-model-item label="Instant delivery" prop="delivery">
<a-switch v-model="form.delivery" />
</a-form-model-item>
<a-form-model-item label="Activity type" prop="type">
<a-checkbox-group v-model="form.type">
<a-checkbox value="1" name="type">
Online
</a-checkbox>
<a-checkbox value="2" name="type">
Promotion
</a-checkbox>
<a-checkbox value="3" name="type">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="Resources" prop="resource">
<a-radio-group v-model="form.resource">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="Activity form" prop="desc">
<a-input v-model="form.desc" type="textarea" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="onSubmit">
Create
</a-button>
<a-button style="margin-left: 10px;" @click="resetForm">
Reset
</a-button>
</a-form-model-item>
</a-form-model>
</template>
<script>
export default {
data() {
return {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
other: '',
form: {
name: '',
region: undefined,
date1: undefined,
delivery: false,
type: [],
resource: '',
desc: '',
},
rules: {
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
region: [{ required: true, message: 'Please select Activity zone', trigger: 'change' }],
date1: [{ required: true, message: 'Please pick a date', trigger: 'change' }],
type: [
{
type: 'array',
required: true,
message: 'Please select at least one activity type',
trigger: 'change',
},
],
resource: [
{ required: true, message: 'Please select activity resource', trigger: 'change' },
],
desc: [{ required: true, message: 'Please input activity form', trigger: 'blur' }],
},
};
},
methods: {
onSubmit() {
this.$refs.ruleForm.validate(valid => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
效果