Vue中表单组件的实现

强调vue语法

createElement 函数是用来生成 HTML DOM 元素的
Vue.js 里面的 createElement 函数,这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。

Vue 的 m o u n t ( ) 为 手 动 挂 载 , 在 项 目 中 可 用 于 延 时 挂 载 ( 例 如 在 挂 载 之 前 要 进 行 一 些 其 他 操 作 、 判 断 等 ) 之 后 要 手 动 挂 载 上 。 n e w V u e 时 , e l 和 mount() 为手动挂载, 在项目中可用于延时挂载( 例如在挂载之前要进行一些其他操作、 判断等) 之后要手动挂载上。 new Vue时, el和 mount()newVueelmount并没有本质上的不同。

this.$destroy()内部銷毀組件

async-validator是一个表单的异步验证的第三方库

// 基本用法
var schema = require('async-validator'); // 引用组件
var descriptor = {
 name: {
  type: "string",
  required: true,
  validator: (rule, value) => value === 'muji',
 }
}; // 定义一个descriptor
var validator = new schema(descriptor); // descriptor分配给schema,创建一个validator
validator.validate({name: "muji"}, (errors, fields) => {
 if(errors) {
  // validation failed, errors is an array of all errors
  // fields is an object keyed by field name with an array of
  // errors per field
 return handleErrors(errors, fields);
 }
  // validation passed
}); // 参数一:要验证的对象、参数二:回调函数

v-mod是语法糖,实现自定义组件双绑需要指定:value和@input即可

其中要思考的问题
1 input是自定义组件,它是怎么实现双向绑定的
2 formItem是怎么知道执行校验的,它是怎么知道input状态的?它是怎么获得对应的数据模型的
3.form是怎么进行全局校验的 它用什么方法把数据模型和校验规则传递给内部组件?

index.vue

<template>

<div>

<h3>KForm表单</h3>

<hr\>

<!-- <k-input :value="model.username" @input="model.username=$event"></k-input> -->

<k-form :model="model" :rules="rules"  ref="kForm">

<k-form-item  label="用户名"  prop="username">

<k-input  v-model="model.username"></k-input>

</k-form-item>

<k-form-item  label="密码"  prop="password">

<k-input  type="password"  v-model="model.password"></k-input>

</k-form-item>

<k-form-item>

<el-button  type="primary" @click="submitForm('kForm')">提交</el-button>

</k-form-item>

</k-form>

  

<h3>Element表单</h3>

<hr>

<el-form :model="model" :rules="rules"  ref="loginForm">

<el-form-item  label="用户名"  prop="username">

<el-input  v-model="model.username"  autocomplete="off"></el-input>

</el-form-item>

<el-form-item  label="确认密码"  prop="password">

<el-input  type="password"  v-model="model.password"  autocomplete="off"></el-input>

</el-form-item>

<el-form-item>

<el-button  type="primary" @click="submitForm('loginForm')">提交</el-button>

</el-form-item>

</el-form>

</div>

</template>

  

<script>

import  KInput  from  './Input.vue'

import  KFormItem  from  './FormItem.vue'

import  KForm  from  './Form.vue'

export  default {

components: {

KInput,

KFormItem,

KForm

},

data () {

return {

// 数据模型

model: { username: 'tom', password: '' },

// 校验规则

rules: {

username: [{ required: true, message: '请输入用户名' }],

password: [{ required: true, message: '请输入密码' }]

}

}

},

methods: {

submitForm (form) {

// 表单全局校验

this.$refs[form].validate(valid => {

if (valid) {

alert('请求登录!')

} else {

alert('校验失败!')

}

})

}

}

}

</script>

  

<style  scoped>

</style>

Form

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

<script>
export default {
  // provide可以跨层级传参给子代
  provide () {
    return {
      form: this
    }
  },
  props: {
    model: {
      type: Object,
      required: true
    },
    rules: {
      type: Object
    }
  },
  methods: {
    async validate (cb) {
      // 執行表單中所有的表单项的校验
      // 返回的 promise的数组
      const tasks = this.$children.filter(item => item.prop).map(item => item.validate())
      // tasks中任意一个错误就校验失败
      // await是直接获取多个promise的结果的,因为Promise.all()返回的也是一个promise所以如果要使用await拿到多个promise的值,
      // 同步化
      const result = await Promise.all(tasks)
      if (result.some(valid => !valid)) {
        // eslint-disable-next-line
        cb(false)
      } else {
        // eslint-disable-next-line
        cb(true)
      }
    }
  }
}
</script>

<style  scoped>

</style>

FormItem

<template>

<div>

<label  v-if="label">{{label}}</label>

<!-- 插槽 -->

<slot></slot>

<!-- 校验错误信息 -->

<p  v-if="errorMessage"  class="error">{{errorMessage}}</p>

</div>

</template>

  

<script>

import  Validator  from  'async-validator'

import { Promise } from  'q'

  

export  default {

inject: ['form'],

props: ['label', 'prop'],

data () {

return {

errorMessage: ''

}

},

created () {

this.$on('validate', this.validate)

},

methods: {

validate () {

return  new  Promise(resolve => {

// 校验规则制定
// [this.prop]计算属性 希望this prop key的值是一个表达式
const  descriptor  = { [this.prop]: this.form.rules[this.prop] }

// 创建校验器

const  validator  =  new  Validator(descriptor)

// 执行校验

validator.validate(

{ [this.prop]: this.form.model[this.prop] },

errors => {

if (errors) {

// 显示错误信息

this.errorMessage  =  errors\[0\].message

resolve(false)

} else {

this.errorMessage  =  ''

resolve(true)

}

}

)

})

}

}

}

</script>

  

<style  scoped>

.error {

color: red;

}

</style>

Input

<template>
  <div>
    <input :type="type" :value="value" @input="onInput">
  </div>
</template>

<script>
export default {
  props: {
    type: {
      type: String,
      default: 'text'
    },
    value: {
      type: String,
      default: ''
    }
  },
  methods: {
    onInput (e) {
      // 通知老爹发生了input事件
      this.$emit('input', e.target.value)

      // 通知FormItem校验
      this.$parent.$emit('validate')
    }
  }
}
</script>

<style  scoped>
</style>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值