学就要入深,一定要自己造出轮子,接下来我们就手动实现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
都需要用到rules
和model
,定义在最外层组件上,便于子组件的使用
上图可以清晰的展示组件之间的关系,并且,通过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
组件中会进行表单校验和错误信息展示。但是model
和rules
都挡在k-form
组件中,我这里使用了provide
和inject
进行组件间传值,在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.$on
和this.$parent.$emit
provide
和inject
,祖先组件与后代组件之间的通信
slot
插槽的引用v-model
双向数据绑定的实现Promise.all
的使用async-validator
校验库的使用
- 组件间传值
- 组件设计,首先尝试着写出使用这个组件的架子,然后根据你如何去使用组件逐个去实现各个组件,明确各个组件的功能,通过组件间的通信连接各个组件