elForm通信原理(required规则的校验)
-
点击 在父组件
el-from上的validate方法,去触发子组件el-form-item上的validate方法- 通过
this.$children拿到子组件 - 遍历所有的子组件,依次调用其valiate方法,进行规则验证
- 如果有一个子组件的验证不通过,就返回false(即验证失败)
- 通过
-
在子组件上的validate验证规则的实现
- 通过
this.$parent拿到父组件form - 通过
form.model[this.prop]拿到父组件上对应项的数据value - 通过
form.rules[this.prop]拿到父组件上对应项的规则rule - 再遍历rule,查看里面是否有
required==true的规则以及value不为空,如果都满足,就表示验证通过,返回true
- 通过
注意:
-
这里的value和rule都是通过
this.prop来拿到,所以可以只用为子元素绑定prop属性即可 -
如果有一个不能直接通过
this.prop拿到,就需要分开写prop属性拿到对应value,rule属性来拿到对应的rule,将在下一个例子详细说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
</head>
<body>
<div id="app">
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item prop="uname">
<input type="text" v-model="form.uname" placeholder="请填写内容"></input>
</el-form-item>
<div style="margin-top: 10px;">
<button @click="submit">提交</button>
</div>
</el-form>
</div>
</body>
<script>
//父组件
Vue.component('el-form', {
props: ['model', 'rules'],
template: `
<div>
<slot></slot>
</div>
`,
methods: {
validate(callback){
//调用子组件的valiate方法
//1.得到子组件
// 方式1.通过ref
// 方式2.通过$children
//2.循环子组件
let isAllOk = true
this.$children.forEach(item=>{
let isOneOk = item.validate()
if(!isOneOk) isAllOk = false
})
callback(isAllOk)
}
}
})
//子组件
Vue.component('el-form-item', {
props: ["prop"],
template: `
<div>
<slot></slot>
</div>
`,
methods: {
validate(){
// console.log('子组件', this)
//0.得到父组件
let form = this.$parent
console.log(form);
//方式1-通过父子通信,子->父通过$emit
//方式2-
//1.得到数据
let value = form.model[this.prop]
//2.得到规则
let rule = form.rules[this.prop]
//3.做判断
//如果存在required为true,并且有值返回true,否则false
if(rule.some(t=>t.required==true) && value!==''){
return true
}else{
false
}
// return true //false
// return false
}
}
})
var vm = new Vue({
el: "#app",
data() {
return {
form: {
uname: ''
},
rules: {
uname: [{required:true}]
}
}
},
methods: {
submit(){
this.$refs.formRef.validate(isValid=>{
if(isValid){
console.log('验证通过')
}else{
console.log('验证不通过')
}
})
}
}
})
</script>
</html>
表单rule与value不一致案例
方式一:表单rule与value的数据结构保持一致
可以看到,data中form和rules对应的数据结构是一致的,所以可以只写prop属性即可
- form.unit <-----> rules.unit
- form.now.unit <-----> rules.now.unit
// form
form: {
unit: '',
now: {
unit: ''
}
},
// rules
rules: {
unit: [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
],
'now.unit': [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
]
}
- 第一项,prop都为
unit- 得到数据:this.form.unit
- 得到规则:this.rules.unit
- 第二项,prop都为
now.unit- 得到数据: this.form.now.unit
- 得到规则: this.rules.now.unit
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.css" rel="stylesheet" />
<style>
.el-button,
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: 100%;
}
</style>
</head>
<body>
<div id="app">
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<!-- 得到数据:this.form.unit -->
<!-- 得到规则:this.rules.unit -->
<el-form-item label="之前单位" prop="unit">
<el-input v-model="form.unit" placeholder="请填写工作单位"></el-input>
</el-form-item>
<!-- 得到数据: this.form.now.unit -->
<!-- 得到规则: this.rules.now.unit-->
<el-form-item label="现在单位" prop="now.unit">
<el-input v-model="form.now.unit" placeholder="请填写工作单位"></el-input>
</el-form-item>
<el-row style="margin-top: 10px">
<el-button type="primary" @click="submit">提交</el-button>
</el-row>
</el-form>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data() {
return {
form: {
unit: '',
now: {
unit: ''
}
},
rules: {
unit: [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
],
'now.unit': [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
]
}
}
},
methods: {
submit() {
this.$refs.formRef.validate(isValid => {
if (isValid) {
this.$message.success('验证通过')
} else {
this.$message.error('验证不通过')
}
})
}
}
})
</script>
</html>
方式一:表单rule与value的数据结构不一致
可以看到,data中form和rules对应的数据结构是不一致的,两个表单项都使用了同一个规则rules.unit,第二个表单项是没有一致对应的
- form.unit <-----> rules.unit
- form.now.unit <-----> rules.unit
- 第一项,prop都为
unit- 得到数据:this.form.unit
- 得到规则:this.rules.unit
- 第二项,需要额外再绑定rules属性
- 得到数据: this.form.now.unit-----
prop='now.unit' - 得到规则: this.rules.unit------
:rules='rules.unit'
- 得到数据: this.form.now.unit-----
...省略其他代码
<body>
<div id="app">
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<!-- 得到数据:this.form.unit -->
<!-- 得到规则:this.rules.unit -->
<el-form-item label="之前单位" prop="unit">
<el-input v-model="form.unit" placeholder="请填写工作单位"></el-input>
</el-form-item>
<!-- 得到数据: this.form.now.unit -->
<!-- 得到规则: this.rules.unit-->
<el-form-item label="现在单位" prop="now.unit" :rules="rules.unit">
<el-input v-model="form.now.unit" placeholder="请填写工作单位"></el-input>
</el-form-item>
<el-row style="margin-top: 10px">
<el-button type="primary" @click="submit">提交</el-button>
</el-row>
</el-form>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data() {
return {
form: {
unit: '',
now: {
unit: ''
}
},
rules: {
unit: [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
]
}
}
},
methods: {
submit() {
this.$refs.formRef.validate(isValid => {
if (isValid) {
this.$message.success('验证通过')
} else {
this.$message.error('验证不通过')
}
})
}
}
})
</script>
</html>
循环表单验证
方式一:循环整个form表单【结果:多个form表单】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js"></script>
<link
href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.css"
rel="stylesheet"
/>
<style>
.el-button,.el-date-editor.el-input, .el-date-editor.el-input__inner{width: 100%;}
</style>
</head>
<body>
<div id="app">
<el-form label-width="100px" ref="formRef" :model="item" :rules="rules" v-for="(item,index) in form.workExperience">
<template >
<h4>工作经历</h4>
<!-- 得到数据:form.workExperience[0].unit -->
<!-- 得到规则:rules.unit -->
<el-form-item label="工作单位" prop="unit">
<el-input v-model="item.unit" placeholder="请填写工作单位"></el-input>
</el-form-item>
<el-form-item label="开始时间" prop="undergoStartTime">
<el-date-picker v-model="item.undergoStartTime" type="date" placeholder="请选择开始时间"></el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="undergoEndTime">
<el-date-picker v-model="item.undergoEndTime" type="date" placeholder="请选择结束时间"></el-date-picker>
</el-form-item>
<el-form-item label="担任职务" prop="job">
<el-input v-model="item.job" placeholder="请选择结束时间"></el-input>
</el-form-item>
<el-form-item label="离职原因" prop="cause">
<el-input v-model="item.cause" placeholder="请填写离职原因"></el-input>
</el-form-item>
</template>
</el-form>
<el-row>
<el-button @click="add">添加工作经历</el-button>
</el-row>
<el-row style="margin-top: 10px;">
<el-button type="primary" @click="submit">提交</el-button>
</el-row>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data() {
return {
form: {
workExperience: [{
unit: '',
isWoke:false,
undergoStartTime: '',
undergoEndTime:'',
job: '',
cause: '',
}]
},
rules: {
unit: [{
required: true,
message: '请输入工作单位',
trigger: 'blur',
}],
undergoStartTime: [{
required: true,
message: '请选择起止时间',
trigger: 'blur',
}],
undergoEndTime: [{
required: true,
message: '请选择结束时间',
trigger: 'blur',
}],
job: [{
required: true,
message: '请输入担任职务',
trigger: 'blur',
}],
cause: [{
required: true,
message: '请选输入离职原因',
trigger: 'blur',
}]
},
}
},
methods: {
add(){
this.form.workExperience.push({
unit: '',
isWoke:false,
undergoStartTime: '',
undergoEndTime:'',
job: '',
cause: '',
})
},
async submit(){
//1.通过回调函数
/*
let isAllOk = true
this.$refs.formRef.forEach(t=>{
t.validate((isOk)=>{
if(!isOk) isAllOk = false
})
})
console.log('isAllOk', isAllOk)
*/
//2.通过Promise.all
/*
let l = []
this.$refs.formRef.forEach(t=>{
let p = t.validate()
l.push(p)
})
Promise.all(l).then(()=>{
console.log('全部成功')
}).catch(()=>{
console.log('存在失败')
})
*/
//2.2通过map优化代码
/*
let l = this.$refs.formRef.map(t=> t.validate())
Promise.all(l).then(()=>{
console.log('全部成功')
}).catch(()=>{
console.log('存在失败')
})
*/
//2.3通过await简化promise接受
/*
let l = this.$refs.formRef.map(t=> t.validate())
try{
await Promise.all(l)
console.log('全部成功')
}catch(err){
console.log('存在失败')
}
*/
// 2.4取消中间变量
try{
await Promise.all(this.$refs.formRef.map(t=> t.validate()))
console.log('全部成功')
}catch(err){
console.log('存在失败')
}
}
}
})
</script>
</html>
方式二:只循环表单项 【结果:一个form表单】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/index.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.1/theme-chalk/index.css" rel="stylesheet" />
<style>
.el-button,
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: 100%;
}
</style>
</head>
<body>
<div id="app">
<el-form label-width="100px" ref="formRef" :model="form" :rules="rules">
<div v-for="(workExperience,index) in form.workExperience" :key="index">
<h4>工作经历</h4>
<!-- 拿到的value:form.workExperience[index].unit -->
<!-- 拿到的rules:rules.unit -->
<el-form-item label="工作单位" :prop="'workExperience.' + index + '.unit'" :rules="rules.unit">
<el-input placeholder="请填写工作单位" v-model="workExperience.unit"></el-input>
</el-form-item>
<el-form-item label="担任职务" :prop="'workExperience.'+index+'.job'" :rules="rules.job">
<el-input placeholder="请选择担任职务" v-model="workExperience.job"></el-input>
</el-form-item>
</div>
</el-form>
<el-row>
<el-button @click="add">添加工作经历</el-button>
</el-row>
<el-row style="margin-top: 10px">
<el-button type="primary" @click="submit">提交</el-button>
</el-row>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data() {
return {
form: {
workExperience: [
{
unit: '',
isWoke: false,
job: ''
}
]
},
rules: {
unit: [
{
required: true,
message: '请输入工作单位',
trigger: 'blur'
}
],
job: [
{
required: true,
message: '请输入担任职务',
trigger: 'blur'
}
]
}
}
},
methods: {
add() {
this.form.workExperience.push({
unit: '',
isWoke: false,
undergoStartTime: '',
undergoEndTime: '',
job: '',
cause: ''
})
},
async submit() {
this.$refs.formRef.validate(isOK => {
if (isOK) {
alert('submit!')
} else {
console.log('error submit!!')
return false
}
})
}
}
})
</script>
</html>