如何用Vue自己写一个简易版elementUI的form组件

完整源代码请移步GitHub: https://github.com/webxing/element_form

要仿照的elementUI的效果:


  
    
  
  
    
  

实现思路

Step1:实现一个支持 v-model 的自定义输入组件

要实现的结果如下:保证 l-input 可以使用 v-model 来进行数据的双向绑定



v-model:

  • 原理:
 
  • 把 inputValue 传给组件 l-input 内部
  • 当组件 l-input 的 input 事件被触发时自动将事件携带的参数赋值给 inputValue

$event:

当在父级组件监听事件的时候,我们可以通过 $event 访问到被抛出的值


代码

l-input 组件实现代码如下:


这个组件内的 必须:

  • 将其 value 特性绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
  export default {
    props: {
      value: {
        type: String,
        default: ''
      },
      type: {
        type: String,
        default: ''
      }
    },
    methods: {
      handlerInput(e) {
        // 通知父组件值更新
        this.$emit('input', e.target.value)

        // 通知 formItem 进行校验
        this.$parent.$emit('validate',e.target.value)
      }
    },
  }

Step2:实现一个支持 负责label标签 以及 显示错误信息的组件

要实现的结果如下:保证 l-form-item 可以显示 label 以及可以对 prop 进行数据校验


  

代码


  import schema from 'async-validator'
  export default {
    inject: ["form"], // 注入form  获取到 form 的 model 以及 rules
    props: {
      label: {
        type: String,
        default: ''
      },
      prop: {
        type: String,
        default: ''
      }
    },

    data() {
      return {
        validateStatus: '',
        validateMsg: ''
      }
    },
    
    created() {
      // 校测到来此 LInput 的检测请求
      this.$on('validate', this.validate)
    },

    mounted() {
      // 挂载到form上时,派发一个添加事件
      // 如果此组件传入了 props ,则需要通知父组件 以放入检测数组
      if (this.prop) {
        this.$parent.$emit("formItemAdd", this)
      }
    },

    methods: {
      validate() {
        // 使用 async-validator 进行校验
        return new Promise((resolve) => {
          console.log('validate -- input 通知我校验数据了', this.form.model[this.prop])
          // 校验规则
          let descriptor = {
            [this.prop]: this.form.rules[this.prop]
          }

          // 校验器
          let validator = new schema(descriptor)

          // 开始校验数据
          validator.validate({[this.prop]: this.form.model[this.prop]}, (error) => {
            if(error) {
              this.validateStatus = 'error'
              this.validateMsg = error[0].message

              resolve(false)
            } else {
              this.validateStatus = ''
              this.validateMsg = ''

              resolve(true)
            }
          })
        })
      }
    },
  }

Step3:实现一个支持 负责label标签 以及 显示错误信息的组件

要实现的结果如下:传入 表单数据对象(ruleForm) 和 表单验证规则(rules)后可以实现表单的数据校验 提供 validate 方法来获取整个表单的验证结果


  
    
  
  
    
  
  
    
  

// 传入的表单数据对象和表单验证规则
ruleForm: {
  name: "",
  pwd: ""
},
rules: {
  name: [
    { required: true, message: "请输入名称" },
    { min: 6, max: 10, message: "请输入6~10位用户名" }
  ],
  pwd: [{ required: true, message: "请输入密码" }]
}
// 调用组件的validate方法获取验证结果
this.$refs.loginForm.validate(valid => {
  if (valid) {
    alert("提交登录!")
  } else {
    console.log("校验失败")
    return false
  }
})

代码


  export default {
    provide() {
      return {
        form: this // 将表单实例传递给后代
      }
    },
    props: {
      model: {
        type: Object,
        required: true
      },
      rules: {
        type: Object
      }
    },
    data() {
      return {
        files: []
      }
    },
    created() {
      // 缓存需要校验的表单项
      this.$on('formItemAdd', item => this.files.push(item))
      console.log(this.files)
    },

    methods: {
      // 将FormItem数组转换为 validate() 返回的promise数组
      // 调用 LForm 组件的 validate 方法可以得到表单数据校验的结果
      async validate(callback) {
        let tasks = this.files.map(item => item.validate())
        console.log(tasks)
        
        // 获取所有结果统一处理
        const results = await Promise.all(tasks)

        let ret = true
        results.forEach(valid => {
          if (!valid) {
            ret = false // 只要一个失败就失败
          }
        })
        callback(ret)
      }
    },
  }

你可能感兴趣的:(如何用Vue自己写一个简易版elementUI的form组件)