element-ui 组件库 el-form 实现

如果使用过 element-ui 组件库的人都知道,Form 表单由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。用法如下:
<template><el-form :model="form" :rules="rules" ref="form"><el-form-item label="用户名" prop="username"><el-input v-model="form.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="form.password"></el-input></el-form-item><el-form-item><button @click="validate">确认提交</button></el-form-item></el-form></template><script>import Form from "./components/ElForm.vue";import FormItem from "./components/ElFormItem.vue";import Input from "./components/ElInput.vue";export default {components: {"el-form": Form,"el-form-item": FormItem,"el-input": Input,},data() {return {form: {username: "",password: "",},rules: {username: [{ required: true, message: "请输入用户名" }],password: [{ required: true, message: "请输入密码" }],},};},methods: {validate() {// form组件中校验是通过this.$refs.form.validate((valid) => {if (valid) {alert("校验通过");} else {alert("校验不通过");}});},},};</script>
今天讲解 el-form,el-form-item,el-input 的基本实现原理。掌握 el-form 组件的设计思想。
你将学会组件之间的数据通信,eventBus、children、provide。
el-form 组件
<template><form onsubmit="return false"><slot></slot></form></template><script>export default {provide() {return {form: this,};},props: {model: {type: Object,},rules: {type: Object,},},methods: {// 在form组件中检查所有的formItem是否全部通过校验validate(cb) {cb(this.$children.every((child) => child.validateStatus !== "error"));},},};</script>
el-form-item 组件
<template><div><label v-if="label">{{ label }}</label><slot></slot><!-- 有错误 显示错误提示信息 --><div v-if="validateStatus === 'error'">{{ validateContent }}</div></div></template><script>import Vue from "vue";Vue.prototype.$bus = new Vue();export default {props: {label: String,prop: String,},inject: ["form"], // 注入父级的实例data() {return {validateStatus: "", // 当前表单是否通过校验validateContent: "", // 当前校验后的信息};},methods: {validate(value) {let rules = this.form.rules[this.prop]; // 获取当前对应的规则rules.forEach((rule) => {// 如果必填 并且没有值,那就出错if (rule.required && !value) {this.validateStatus = "error";this.validateContent = rule.message;} else {this.validateStatus = "";this.validateContent = "";}});},},mounted() {this.$bus.$on("input", (data) => {if (this._uid === data.id) {// 说明更改的是当前自己的输入框this.validate(data.value);}});},};</script>
el-input 组件
<template><input type="text" :value="inputValue" ="handleInput" /></template><script>export default {props: {value: String,},data() {return { inputValue: this.value };},methods: {handleInput(e) {// 更新数据this.inputValue = e.target.value;this.$bus.$emit("input", {id: this.$parent && this.$parent._uid, // 为了标识是哪个输入框value: this.inputValue,}); // 发射输入事件},},};</script>
表单校验这里也只是简单的判断,但是 Element 官网使用的是第三方的 npm 包。更多高级用法可参考 async-validator。
上面演示的代码是 vue2 版本,vue3 已经不在提供 eventBus 了,没有 $on 这个 API 了,推荐使用第三方的 npm 包 mitt 编写,源码也是这样的。
评论
