![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/554d78234d5769314a1102692eac10a9.gif)
1. 入口文件
- model,rules 传递给form组件
- 通过refs调用子组件的validate方法
<c-form :model="ruleForm" :rules="rules" ref="CForm">
<c-form-item label="用户名" prop="name">
<c-input v-model="ruleForm.name"></c-input>
</c-form-item>
<c-form-item label="密码" prop="password">
<c-input v-model="ruleForm.password"></c-input>
</c-form-item>
<button @click="submit('CForm')">新建</button>
</c-form>
export default {
data() {
return {
ruleForm: { name: '', password: '' },
rules: {
name: [{ required: true, message: '请输入用户名', trigger: 'change' }],
password: [{ required: true, message: '请输入密码', trigger: 'change' }]
}
}
},
methods: {
submit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!')
} else {
console.log('error submit!!')
return false
}
})
}
}
}
2. c-form
- provide / inject 祖先组件向子孙组件注入一个依赖
- 执行form-item的校验方法
<div class="c-form">
<slot></slot>
</div>
export default {
provide() {
return {
form: this // 将this传递给子组件,命名为form
}
},
props: {
model: { type: Object, required: true },
rules: { type: Object }
},
methods: {
async validate(callback) {
const tasks = this.$children
.filter(item => item.prop) // 过滤有prop的子组件
.map(item => item.validate()) // 执行校验,返回Promise
const result = await Promise.all(tasks) // 执行异步
if (result.some(validate => !validate)) { // 检验是否包含false的验证
callback(false)
} else {
callback(true)
}
}
}
}
2. c-form-item
<div class="c-form-item">
<span>{{label}}</span>
<slot></slot>
<p :class="{'error' : errorMessage}">{{errorMessage}}</p>
</div>
export default {
inject: ['form'],
props: ['label', 'prop'],
created() {
this.$on('validate', this.validate)
},
data() {
return { errorMessage: '' }
},
methods: {
validate() {
return new Promise(resolve => {
const descriptor = { [this.prop]: this.form.rules[this.prop] }
const validator = new Validator(descriptor)
validator.validate({ [this.prop]: this.form.model[this.prop] }, (errors) => {
if (errors) {
this.errorMessage = errors[0].message
resolve(false)
} else {
this.errorMessage = ''
resolve(true)
}
})
})
}
}
}
3. c-input
- v-model 的本质是v-bind和@input的结合
<div class="c-input">
<input :value="value" :type="type" @input="inputHandle">
</div>
export default {
props: {
type: {
type: String,
default: 'text'
},
value: {
type: String
}
},
methods: {
inputHandle(e) {
this.$emit('input', e.target.value)
this.$parent.$emit('validate')
}
}
}
GitHub链接