这篇文章主要给大家介绍了关于Vue模仿ElementUI的form表单的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
实现要求
模仿 ElementUI 的表单,分为四层结构:index 组件、Form 表单组件、FormItem 表单项组件、Input 和 CheckBox 组件,具体分工如下:
index 组件:
实现:分别引入 Form 组件、FormItem 组件、Input 组件,实现组装;
Form 表单组件:
实现:预留插槽、管理数据模型 model、自定义校验规则 rules、全局校验方法 validate;
FormItem 表单项组件:
实现:预留插槽、显示 label 标签、执行数据校验、显示校验结果;
Input 和 CheckBox 组件:
实现:绑定数据模型 v-model、通知 FormItem 组件执行校验;
Input 组件
具体实现如下:
1、自定义组件要实现 v-model 必须实现 :value 和 @input。
2、当输入框中的数据发生变化时,通知父组件执行校验。
3、当 Input 组件绑定的 type 类型为 password 时,在组件内部使用 v-bind="$attrs" 获取 props 之外的内容。
4、设置 inheritAttrs 为 false, 从而避免顶层容器继承属性。
Input 组件实现:
<template> <div> <input :value="value" @input="onInput" v-bind="$attrs" /> </div></template><script>export default { inheritAttrs: false, // 避免顶层容器继承属性 props: { value: { type: String, default: "" } }, data() { return {}; }, methods: { onInput(e) { // 通知父组件数值发生变化 this.$emit("input", e.target.value); // 通知 FormItem 执行校验 // 这种写法不健壮,因为 Input 组件和 FormItem 组件之间可能会隔代 this.$parent.$emit("validate"); } }};</script><style scoped></style>注意:代码中使用 this.$parent 派发事件,这种写法不健壮,当 Input 组件和 FormItem 组件之间隔代时会出现问题。具体解决方式见文章尾部代码优化部分。
CheckBox 组件
1、自定义实现 checkBox 的双向数据绑定,和 input 大同小异,必须实现 :checked 和 @change。
CheckBox 组件实现:
<template> <section> <input type="checkbox" :checked="checked" @change="onChange" /> </section></template><script>export default { props: { checked: { type: Boolean, default: false } }, model: { prop: "checked", event: "change" }, methods: { onChange(e) { this.$emit("change", e.target.checked); this.$parent.$emit("validate"); } }};</script><style scoped></style>FormItem 组件
具体实现如下:
1、给 Input 组件或者 CheckBox 组件预留插槽。
2、如果用户在组件上设置 label 属性,要展示 label 标签。
3、监听校验事件,并执行校验(使用 async-validator 插件进行校验)。
4、如果不符合校验规则,需要显示校验结果。
在开发的过程中,我们需要思考几个问题:
1、在组件内部,如何得到需要校验的数据和校验规则?
2、在 Form 表单中会有多个菜单项,如:用户名、密码、邮箱...等等,那么 FormItem 组件是如何得知现在校验的是哪个菜单呢?
FormItem 组件实现:
<template> <div> <div> <label v-if="label" :style="{ width: labelWidth }">{{ label }}:</label> <slot></slot> </div> <p v-if="errorMessage">{{ errorMessage }}</p> </div></template><script>import Schema from "async-validator";export default { inject: ["formModel"], props: { label: { type: String, default: "" }, prop: String }, data() { return { errorMessage: "", labelWidth: this.formModel.labelWidth }; }, mounted() { // 监听校验事件,并执行校验 this.$on("validate", () => { this.validate(); }); }, methods: { validate() { // 执行组件的校验 // 1、获取数据 const values = this.formModel.model[this.prop]; // 2、获取校验规则 const rules = this.formModel.rules[this.prop];

