ELement-UI中Form表单的实现

学就要入深,一定要自己造出轮子,接下来我们就手动实现Element-ui中form表单的实现

1、表单组件的使用

<template>
  <div class="form-index">
    <k-form :model="ruleForm" :rules="rules" ref="form">
      <k-form-item label="用户名" prop="username">
        <k-input v-model="ruleForm.username" placeholder="请输入用户名"></k-input>
      </k-form-item>
      <k-form-item label="密码" prop="password">
         <k-input v-model="ruleForm.password" type="password" placeholder="请输入密码"></k-input>
      </k-form-item>
      <k-form-item>
        <button @click="submitForm">login</button>
      </k-form-item>
    </k-form>
  </div>
</template>

<script>
import KForm from './KForm'
import KFormItem from './KFormItem'
import KInput from './KInput'
export default {
  name: 'kFormIndex',
  data () {
    return {
      ruleForm: {
        username: '',
        password: ''
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' }
        ]
      }
    }
  },
  components: {
    KForm,
    KFormItem,
    KInput
  },
  methods: {
    submitForm () {
      this.$refs.form.validate(result => {
        if (result) {
          alert('success')
        } else {
          alert('failure')
        }
      })
    }
  }
}
</script>

通过上面的代码,我们可以看出,表单组件的使用是有三层结构。并且数据的检验规则rules和表单数据model都在最外层k-form表单上,原因是在k-form-item都需要用到rulesmodel,定义在最外层组件上,便于子组件的使用
在这里插入图片描述
上图可以清晰的展示组件之间的关系,并且,通过slot插槽构建组件之间的关系,接下来我们就看下各个组件的实现

k-input组件

<template>
  <div>
    <input v-bind="$attrs" :value="value" @input="inputHandle">
  </div>
</template>

<script>
export default {
  inheritAttrs: false, //默认继承的属性去掉
  name: 'kInput',
  props: {
    value: {
      type: String
    }
  },
  methods: {
    inputHandle (e) {
      this.$emit('input', e.target.value)
      // 分发检验事件
      this.$parent.$emit('validate')
    }
  }
}
</script>

<style lang="scss" scoped>

</style>

  • 通过表单组件的效果,可以看到k-input实现的双向数据绑定。在外层使用的v-model其实就是一个语法糖(绑定value和监听input事件),在k-input组件中,我们需要接受prop和分发input事件来实现双向数据绑定。
  • $attrs可以获取来自父组件传过来的值,并展开放在当前标签上。
  • this.$parent.$emit('validate'),每次input输入框的值发生改变都需要进行校验,由于父组件中是使用slot插槽,所以在父组件中使用this.$on('validate', this.validate)进行监听。

k-form-item

<template>
  <div>
    <span v-if="label">{{ label }}</span>
    <slot></slot>
    <p v-if="errMessage">{{errMessage}}</p>
  </div>
</template>

<script>
import Schema from 'async-validator'
export default {
  name: 'kFormItem',
  inject: ['form'],
  props: {
    label: {
      type: String,
      default: ''
    },
    prop: {
      type: String
    }
  },
  data () {
    return {
      errMessage: ''
    }
  },
  mounted () {
    this.$on('validate', () => { this.validate() })
  },
  methods: {
    validate () {
      // 做校验
      const value = this.form.model[this.prop]
      const rules = this.form.rules[this.prop]
      const desc = { [this.prop]: rules }
      const schema = new Schema(desc)
      return schema.validate({ [this.prop]: value }, error => {
        if (error) {
          this.errMessage = error[0].message
        } else {
          this.errMessage = ''
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>

</style>

k-form-item组件中会进行表单校验和错误信息展示。但是modelrules都挡在k-form组件中,我这里使用了provideinject进行组件间传值,在k-form-item组件中就可以获取校验规则,使用async-validator校验库进行校验。

k-form

<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: 'kForm',
  provide () {
    return {
      form: this
    }
  },
  props: {
    model: {
      type: Object
    },
    rules: {
      type: Object
    }
  },
  methods: {
    validate (cb) {
      const tasks = this.$children
        .filter(item => item.prop)
        .map(item => item.validate())
      Promise.all(tasks)
        .then(() => cb(new Error(true)))
        .catch(() => {
          const flag = false
          cb(flag)
        })
    }
  }
}
</script>

<style lang="scss" scoped></style>

k-form表单中提供了一个validate方法,该方法校验所以表单校验是否都通过。在使用k-form表单的时候,注册或者登录的时候判断所以表单的输入是否正确

效果图

在这里插入图片描述

总结

  • 使用到的技术点
    • 组件间传值
      • props,父组件通过属性的方式传递给子组件
      • $emit,子组件通过分发事件传值,父组件去监听接收值,还可以使用this.$onthis.$parent.$emit
      • provideinject,祖先组件与后代组件之间的通信
    • slot插槽的引用
    • v-model双向数据绑定的实现
    • Promise.all的使用
    • async-validator校验库的使用
  • 组件设计,首先尝试着写出使用这个组件的架子,然后根据你如何去使用组件逐个去实现各个组件,明确各个组件的功能,通过组件间的通信连接各个组件
发布了17 篇原创文章 · 获赞 0 · 访问量 402

猜你喜欢

转载自blog.csdn.net/k19970320j/article/details/104387186