vue组件化开发实战 - 实现简易ElementUI的Form表单组件
Posted juyouji
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue组件化开发实战 - 实现简易ElementUI的Form表单组件相关的知识,希望对你有一定的参考价值。
Input 组件
功能:
- 进行数据双绑
- 通知FormItem组件校验
<template>
<div>
<input :type="type" :value="value" @input="onInput" v-bind="$attrs" >
</div>
</template>
<script>
export default {
inheritAttrs:false,
props:{
value:{
type: String,
default: ''
},
type:{
type: String,
default: 'text'
},
},
methods:{
onInput(e){
this.$emit('input',e.target.value);
// 让父组件自己派发自己监听该valid事件进行校验。
this.$parent.$emit('valid');
}
}
}
</script>
$attrs
和 v-bind="$attrs"
使用
$attrs
是vue内置属性用来存储外部传向一个组件但没有被props接收的属性。- 这些属性都有非prop特性:
1. 会被自动添加到组件的根元素上。
2. 默认情况下,非prop特性的属性会覆盖组件根元素上同名的内容。 对于style
和class
有特殊处理:进行合并(但是如果是同名样式则会覆盖)
3. 如果不希望组件根元素继承非prop特性,可以在组件配置项中配置inheritAttrs:false
( 该API对style和class没影响 )
v-bind="$attrs"
是对$attrs
进行解构赋值的一种方法,解构成:key="value"
形式。
FormItem 组件
功能:
- 校验
- label显示
- 错误显示
<template>
<div>
<label v-if="label">{{label}}</label>
<slot></slot>
<p v-if="error">{{error}}</p>
</div>
</template>
<script>
import Schema from 'async-validator'; // 校验包
export default {
inject:['form'],
props:{
label:{
type:String,
default:''
},
prop:{
type:String,
default:''
}
},
data(){
return {
error:''
}
},
mounted(){
this.$on('valid',()=>{
this.validate();
})
},
methods:{
validate(){
const rules = this.form.rules[this.prop];
const value = this.form.model[this.prop];
const schema = new Schema({[this.prop]:rules});
// 返回Promise<Boolean>
return schema.validate({[this.prop]:value},(errors)=>{
if(errors){
this.error = errors[0].message;
}else{
this.error = '';
}
})
}
}
}
</script>
Form 组件
功能:
- 提供数值
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
provide(){
return {
form:this // 把form组件实例传给后代,后代可以通过该实例访问该组件上的属性 model、rule ...
}
},
props:{
model:{
type:Object,
reuqired:true
},
rules:{
type:Object,
}
},
methods:{
validate(cb){
const checkRes = this.$children
.filter(item => item.prop)
.map(item => item.validate());
Promise.all(checkRes)
.then(()=>cb(true))
.catch(()=>cb(false));
}
}
}
</script>
通用库开发中常用的跨层级传参方法 provide / inject
- 祖代设置
provide
配置项,该项类似于data
的用法,但是它的数据是给后代用的,不是给自己用的。 后代通过
inject
配置项获取祖代提供的数据。inject: ['form'] // 祖代provide中的key值
通过该方式可以避免第三方库的引入如vuex,如果层级深也不需要通过
props
的方法进行繁琐的传递。
使用
<template>
<div>
<Form :model="model" :rules="rules" ref="myform">
<FormItem label="用户名" prop="username">
<Input v-model="model.username" placeholder="输入用户名" @ev="func" />
</FormItem>
<FormItem label="密码" prop="password" >
<Input v-model="model.password" placeholder="输入密码" type="password" @ev="func" />
</FormItem>
<FormItem >
<button @click="submitForm('myform')">提交</button>
</FormItem>
</Form>
</div>
</template>
<script>
import Input from '@/components/form/Input';
import Form from '@/components/form/Form';
import FormItem from '@/components/form/FormItem';
export default {
components:{
Input,
Form,
FormItem
},
data(){
return{
model:{
username:'',
password:'',
},
rules:{
username:[{required:true,message:'用户名必填'}],
password:[{required:true,message:'密码必填'}],
},
}
},
methods:{
submitForm(form){
this.$refs[form].validate(valid=>{
if(valid){
alert('校验通过');
}else{
alert('校验失败');
}
})
}
}
}
</script>
问题总结
- 为什么数据模型model放在form上?
为了验证方便,From内的FormItem验证可能有很多,如果都写在FormItem上会很繁琐。 - FormItem上为什么要写prop?
为了判别是对model里的哪部分进行校验,也是通过这个prop去获取规则中的key。
以上是关于vue组件化开发实战 - 实现简易ElementUI的Form表单组件的主要内容,如果未能解决你的问题,请参考以下文章
Vue 开发实战实战篇 # 33:更加精细化的权限设计(权限组件权限指令)