• el-form:管理数据模型(model)和校验规则(rules),提供全局的校验方法(validate)
  • el-form-item:显示 label 标签,执行校验(prop),显示校验结果
  • element:绑定数据模型(v-model),通知 formItem 进行校验

    1. <template>
    2. <div>
    3. <el-form :model="ruleForm" :rules="rules" ref="ruleForm">
    4. <el-form-item label="用户名" prop="name">
    5. <el-input v-model="ruleForm.name"></el-input>
    6. </el-form-item>
    7. <el-form-item label="密码" prop="password">
    8. <el-input type="password" v-model="ruleForm.password"></el-input>
    9. </el-form-item>
    10. <el-form-item>
    11. <el-button @click="login('ruleForm')">登录</el-button>
    12. </el-form-item>
    13. </el-form>
    14. </div>
    15. </template>
    16. <script>
    17. export default {
    18. data() {
    19. return {
    20. // 数据模型
    21. ruleForm: {
    22. name: "",
    23. password: ""
    24. },
    25. // 校验规则
    26. rules: {
    27. name: [{ required: true, message: "请输入用户名" }],
    28. password: [{ required: true, message: "请输入密码" }]
    29. }
    30. };
    31. },
    32. methods: {
    33. login(formName) {
    34. this.$refs[formName].validate(valid => {
    35. if (valid) {
    36. alert("submit!");
    37. } else {
    38. alert("error submit!!");
    39. }
    40. });
    41. }
    42. }
    43. };
    44. </script>
    1. <!--MyInput.vue-->
    2. <template>
    3. <div>
    4. <input :type="type" :value="value" @input="inputHandler" />
    5. </div>
    6. </template>
    7. <script>
    8. export default {
    9. name: "MyInput",
    10. props: {
    11. type: {
    12. type: String,
    13. default: "text"
    14. },
    15. value: {
    16. type: String,
    17. default: ""
    18. }
    19. },
    20. methods: {
    21. inputHandler(e) {
    22. // 仅派发事件
    23. this.$emit("input", e.target.value);
    24. // 通知校验
    25. // 为什么这里是this.$parent.$emit,而不是this.$emit?
    26. this.$parent.$emit("validate");
    27. }
    28. }
    29. };
    30. </script>
    1. <!--MyFormItem.vue-->
    2. <template>
    3. <div>
    4. <label v-if="label">{{label}}</label>
    5. <div>
    6. <!--这里的插槽插入MyInput.vue内容-->
    7. <slot></slot>
    8. <!-- 校验错误信息 -->
    9. <p v-if="validateStatus === 'error'">{{errorMes}}</p>
    10. </div>
    11. </div>
    12. </template>
    13. <script>
    14. // 借助“async-validator”进行表单校验
    15. import Schema from "async-validator";
    16. export default {
    17. name: "MyFormItem",
    18. // 注入'from',为了使用form提供的数据模型【model】和校验规则【rules】
    19. inject: ["form"],
    20. props: {
    21. label: {
    22. type: String,
    23. default: ""
    24. },
    25. // 用于获取指定字段值和校验规则
    26. prop: {
    27. type: String,
    28. default: ""
    29. }
    30. },
    31. data() {
    32. return {
    33. errMes: ""
    34. };
    35. },
    36. mounted() {
    37. // 监听Input组件的“this.$parent.$emit(’validate‘)”
    38. // 因为MyFormItem组件的input位置一开始只是个插槽,没有<my-input/>标签,所以无法以"<my-input @validate=''/>"监听事件
    39. this.$on("validate", () => {
    40. this.validate();
    41. });
    42. },
    43. methods: {
    44. // 单项校验
    45. validate() {
    46. // 1.获取值和校验规则
    47. const value = this.form.model[this.prop];
    48. const rule = this.form.rules[this.prop];
    49. // 2.创建Schema实例 {username: rules}
    50. const schema = new Schema({ [this.prop]: rule });
    51. // 3.执行校验,校验对象,回调函数
    52. // validate返回校验结果Promise
    53. return schema.validate({ [this.prop]: value }, errors => {
    54. if (errors) {
    55. this.errMes = errors[0].message;
    56. } else {
    57. this.errMes = "";
    58. }
    59. });
    60. }
    61. }
    62. };
    63. </script>
    1. <!--MyForm.vue-->
    2. <template>
    3. <div>
    4. <!-- 插入<my-form-item/>的内容 -->
    5. <slot></slot>
    6. </div>
    7. </template>
    8. <script>
    9. export default {
    10. name: "MyForm",
    11. // 把form实例提供出去,以便后代组件使用它的数据模型和校验规则
    12. provide() {
    13. return {
    14. form: this
    15. };
    16. },
    17. props: {
    18. model: {
    19. type: Object,
    20. required: true
    21. },
    22. rules: {
    23. type: Object
    24. }
    25. },
    26. methods: {
    27. validate(cb) {
    28. // 全局校验
    29. // 1.不是所有项都需要校验, MyFormItem有prop属性才需要校验
    30. // 2. tasks是promise数组
    31. const tasks = this.$children.filter(item => item.prop).map(item => item.validate())
    32. // 3. 所有MyFormItem必须全通过, 整个表单才是验证通过
    33. Promise.all(tasks)
    34. .then(() => cb(true))
    35. .catch(() => cb(false));
    36. }
    37. }
    38. };
    39. </script>

    参考资料

  1. 模仿Element-UI设计一个Vue的Form表单组件