实现表单组件 #
- 组件结构目录
├── App.vue ├── components │ ├── Form.vue │ ├── FormItem.vue │ └── Input.vue └── package.json
表单组件的使用 #
- Form 提供组件的数据
- FormItem 实现表单校验功能
- Input 输入内容时让FormItem发生校验
使用组件的方式 #
<template>
<el-form :model="form" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" ></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form.password" ></el-input>
</el-form-item>
<el-form-item>
<el-form-item>
<button>确认提交</button>
</el-form-item>
</el-form>
</template>
<script>
import Form from './components/Form';
import FormItem from './components/FormItem';
import Input from './components/Input.vue';
export default {
components:{
'el-form':Form,
'el-form-item':FormItem,
'el-input':Input
},
data(){
return {
form:{
username:'',
password:''
},
rules:{
username:[
{required:true,message:'请输入用户名'}
],
password:[
{required:true,message:'请输入密码'}
]
}
}
}
}
</script>Form组件的基本结构 #
<template>
<form onsubmit="return false">
<slot></slot>
</form>
</template>
<script>
export default {
props:{
model:{
type:Object
},
rules:{
type:Object
}
}
}
</script>FormItem组件结构 #
<template>
<div>
<label v-if="label">{{label}}</label>
<slot></slot>
<div>校验文字</div>
</div>
</template>
<script>
export default {
props:{
label:String,
prop:String
}
}
</script>Input组件结构 #
<template>
<input type="text" :value="inputValue">
</template>
<script>
export default {
props:{
value:String
},
data(){
return {inputValue:this.value}
}
}
</script>实现组件间的数据传递 #
- 为了在formItem中可以拿到form组件中的数据
provide(){ return { form:this } },
我们在form组件中直接将当前实例暴露出去
- 为了能实现input组件和formItem间的通信
import Vue from 'vue'; Vue.prototype.$bus = new Vue(); export default { props:{ label:String, prop:String }, mounted(){ this.$bus.$on('input',(value)=>{ console.log(value) }); } }
我们在formItem组件中,通过eventsBus订阅input事件
- 在input组件中监听输入事件进行数据的发射
<input type="text" :value="inputValue" @input="handleInput"> handleInput(e){ // 更新数据 this.inputValue = e.target.value; this.$bus.$emit('input',{ id:this.$parent && this.$parent._uid,// 为了标识是哪个输入框 value:this.inputValue }); // 发射输入事件 }
- 在formItem中进行数据校验
<template> <div> <label v-if="label">{{label}}</label> <slot></slot> <!-- 有错误 显示错误提示信息 --> <div v-if="validateStatus === 'error'"> {{validateContent}} </div> </div> </template> <script> import Vue from 'vue'; Vue.prototype.$bus = new Vue(); export default { props:{ label:String, prop:String }, inject:['form'], // 注入父级的实例 data(){ return { validateStatus:'', // 当前表单是否通过校验 validateContent:'' // 当前校验后的信息 } }, methods:{ validate(value){ let rules = this.form.rules[this.prop]; // 获取当前对应的规则 rules.forEach(rule=>{ // 如果必填 并且没有值,那就出错 if(rule.required && !value){ this.validateStatus = 'error'; this.validateContent = rule.message }else{ this.validateStatus = ''; this.validateContent = ''; } }) } }, mounted(){ this.$bus.$on('input',(data)=>{ if(this._uid === data.id){ // 说明更改的是当前自己的输入框 this.validate(data.value); } }); } } </script>
到目前为止基本的校验功能已经实现啦
当点击按钮时校验当前表单是否验证成功 #
<el-form :model="form" :rules="rules" ref="form">
<button @click="validate">确认提交</button>
validate(){ // form组件中校验是通过
this.$refs.form.validate((valid)=>{
if(valid){
alert('校验通过')
}else{
alert('校验不通过')
}
});
}
// 在form组件中检查所有的formItem是否全部通过校验
validate(cb){
cb(this.$children.every(child=>child.validateStatus!='error'))
}