1楔子
最近组里在推进和沉淀一些通用的VUE UI组件,所以学习和参考了elementUI的实现方式。form表单其实是很常用的一种基础组件。今天就来研究下里面的实现
2 需要用到的知识点
1. provide inject
它是一种祖先向后代传递数据的一种方式。说到组件与组件之间的通信,有传统的props属性传递,复杂一点用ebus,大型复杂项目推进vuex。
initInjects(vm) // 在初始化data之前,也就是在data中是可以使用祖先注入的变量的
...
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');
2. $on $emit
vue的通过自定义事件,进行子到父的消息传递。
3. inheritAttrs
设置是否默认继承父组件的属性。一般设置为false,然后通过v-bind="$attrs",绑定到需要的地方。如果不设置的话,会默认在组件的最外层dom设置。
4 slot相关
默认插槽 具名插槽 作用域插槽,具体参考文档
5 async-validator
一个异步校验库,这里可以将这块的实现和form本身的代码拆开来,难度就会减少很多
3 demo
// MfInput
<template>
<div class="mf-input">
<input :value="value" @input="onInput" v-bind="$attrs">
</div>
</template>
<script>
export default {
inheritAttrs: false,
name: 'MfInput',
props: {
value: {
type: String,
default: ''
},
},
methods: {
onInput(e) {
this.$emit('input', e.target.value)
this.$parent.$emit('validate')
}
},
}
</script>
// MfFormitem
<template>
<div class="mf-formitem">
<label v-if="label">{{label}}</label>
<slot></slot>
<div v-if="errorMsg">{{errorMsg}}</div>
</div>
</template>
<script>
import schema from 'async-validator'
export default {
name: 'MfFormItem',
inject: ['form'],
props: {
label: {
type: String,
default: ''
},
prop: {
type: String,
default: ''
}
},
data() {
return {
errorMsg: ''
}
},
mounted(){
this.$on('validate', () => this.validate())
},
methods: {
validate() {
const value = this.form.model[this.prop]
const rule = this.form.rules[this.prop]
console.log(value, rule)
let validator = new schema({[this.prop]: rule})
return validator.validate({[this.prop]: value}, (errors, fields) => {
if( errors ){
this.errorMsg = errors[0].message
} else {
this.errorMsg = ''
}
})
}
},
}
</script>
// MfForm
<template>
<div class="mf-form">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'MfForm',
props: {
model: {
type: Object,
required: true,
default: () => {}
},
rules: {
type: Object,
default: () => {}
},
},
provide(){
return {
form: this
}
},
methods: {
validate(cb) {
let tasks = this.$children.filter((item) => item.prop).map((item) => item.validate())
Promise.all(tasks).then(function() {
cb(true)
}).catch(function() {
cb(false)
})
}
},
}
</script>
4 后记
将第二部分的知识点理解之后再去看element的form实现,就会感觉很通畅了。