前言
实现一个跟Element-UI类似的表单组件,让我们可以了解开发通用组件的流程。 效果:Element表单
通用表单组件
- Index
<template>
<el-form :model="model" :reules="rules" ref="loginForm">
<el-form-item prop="username">
<el-input t ype="text" v-model="model.username" plachedor="请输入用户名"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="model.password" plachedor="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<button @click="login">登录</button>
</el-form-item>
</el-form>
</template>
<script>
import elForm from 'el-form'
import elFormItem from 'el-form-item'
import elInput from 'el-input.vue'
export default{
components:{
elForm,
ekFormItem,
elInput
},
data(){
return{
model:{
username:"",
password:""
},
rules:{
username:[{required:true,message:"必须输入用户名"}],
password:[{required:true,message:"必须输入密码"}]
}
}
},
methods:{
login(){
this.$refs.loginForm.validate(isValid=>{
if(isValid){
alert("登录成功")
}else{
alert("登录失败")
}
})
}
}
}
</script>
- el-form 指定数据,校验规则
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default{
provide(){
return{
form:this //provide进行隔代传参。把整体内容进行传参,方便管理。因为传入的是响应式对象,所以接收方也是响应式的。
}
},
props:{
model:{
type:Object,
required:true
},
rules:Object
},
methods:{
//cb是整体表单提交的回调函数
validate(cb){
//所有子组件进行校验,过滤掉不需要校验的值
const tasks = this.$children.filter(item=>item.prop)
.map(item=>item.validate())
//tasks返回的是Promise数组,使用Promise.all进行并发处理
Promise.all(tasks).then(()=>{
cb(true)
}).catch(()=>{
cb(false)
})
}
}
}
</script>
- el-form-item
<template>
<div>
<lable v-if="label">{{label}}</label>
<slot></slot>
<p v-if="error">{{error}}</p>
</div>
</template>
<script>
import Validator from 'async-validator' //使用async-validator库进行校验 npm install async-validator
export default{
inject:['form'],
props:{
label:{
type:String,
default:""
},
prop:{
type:String//prop的作用是获取到具体哪一项的内容数据
}
},
data(){
return{
error:""
}
},
mounted(){
//监听校验
this.$on("validate",()=>{
this.validate()
})
},
methods:{
validate(){
const value = this.form.model[this.prop]//当前项校验规则
const rules = this.form.rules[this.prop]//当前项值
const validator = new Validator({[this.prop]:rules})//创建一个校验器实例
//校验,返回Promise
return validator.validate({[this.prop]:value},errors=>{
if(errors){
this.error = errors[0].message
}else{
this.error = ""
}
})
}
}
}
</script>
- el-input
<template>
<div>
<input :type="type" :value="value" @input="onInput" v-bind="$attrs">
</div>
</template>
<script>
export default{
props:{
type:{
type:String,
default:"text"
},
value:{
type:String,
default:""
}
},
methos:{
onInput(e){
this.$emit("input",e.target.value)
this.$parent.$emit("validate") //事件的派发者与监听者必须是同一角色。因为父组件的内容是使用slot进行内容分发,所以要使用$parent指向父级。$parent指FormItem
}
}
}
</script>
弹窗组件
弹窗这类组件的特点是它们在当前vue实例之外独立存在,通常挂载于body;它们是通过js动态创建的,不需要在任何组件中声明。