- el-form:管理数据模型(model)和校验规则(rules),提供全局的校验方法(validate)
- el-form-item:显示 label 标签,执行校验(prop),显示校验结果
element:绑定数据模型(v-model),通知 formItem 进行校验
<template>
<div>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm">
<el-form-item label="用户名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="ruleForm.password"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="login('ruleForm')">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
// 数据模型
ruleForm: {
name: "",
password: ""
},
// 校验规则
rules: {
name: [{ required: true, message: "请输入用户名" }],
password: [{ required: true, message: "请输入密码" }]
}
};
},
methods: {
login(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
alert("submit!");
} else {
alert("error submit!!");
}
});
}
}
};
</script>
<!--MyInput.vue-->
<template>
<div>
<input :type="type" :value="value" @input="inputHandler" />
</div>
</template>
<script>
export default {
name: "MyInput",
props: {
type: {
type: String,
default: "text"
},
value: {
type: String,
default: ""
}
},
methods: {
inputHandler(e) {
// 仅派发事件
this.$emit("input", e.target.value);
// 通知校验
// 为什么这里是this.$parent.$emit,而不是this.$emit?
this.$parent.$emit("validate");
}
}
};
</script>
<!--MyFormItem.vue-->
<template>
<div>
<label v-if="label">{{label}}</label>
<div>
<!--这里的插槽插入MyInput.vue内容-->
<slot></slot>
<!-- 校验错误信息 -->
<p v-if="validateStatus === 'error'">{{errorMes}}</p>
</div>
</div>
</template>
<script>
// 借助“async-validator”进行表单校验
import Schema from "async-validator";
export default {
name: "MyFormItem",
// 注入'from',为了使用form提供的数据模型【model】和校验规则【rules】
inject: ["form"],
props: {
label: {
type: String,
default: ""
},
// 用于获取指定字段值和校验规则
prop: {
type: String,
default: ""
}
},
data() {
return {
errMes: ""
};
},
mounted() {
// 监听Input组件的“this.$parent.$emit(’validate‘)”
// 因为MyFormItem组件的input位置一开始只是个插槽,没有<my-input/>标签,所以无法以"<my-input @validate=''/>"监听事件
this.$on("validate", () => {
this.validate();
});
},
methods: {
// 单项校验
validate() {
// 1.获取值和校验规则
const value = this.form.model[this.prop];
const rule = this.form.rules[this.prop];
// 2.创建Schema实例 {username: rules}
const schema = new Schema({ [this.prop]: rule });
// 3.执行校验,校验对象,回调函数
// validate返回校验结果Promise
return schema.validate({ [this.prop]: value }, errors => {
if (errors) {
this.errMes = errors[0].message;
} else {
this.errMes = "";
}
});
}
}
};
</script>
<!--MyForm.vue-->
<template>
<div>
<!-- 插入<my-form-item/>的内容 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "MyForm",
// 把form实例提供出去,以便后代组件使用它的数据模型和校验规则
provide() {
return {
form: this
};
},
props: {
model: {
type: Object,
required: true
},
rules: {
type: Object
}
},
methods: {
validate(cb) {
// 全局校验
// 1.不是所有项都需要校验, MyFormItem有prop属性才需要校验
// 2. tasks是promise数组
const tasks = this.$children.filter(item => item.prop).map(item => item.validate())
// 3. 所有MyFormItem必须全通过, 整个表单才是验证通过
Promise.all(tasks)
.then(() => cb(true))
.catch(() => cb(false));
}
}
};
</script>
参考资料