完整源代码请移步GitHub: https://github.com/webxing/element_form
要仿照的elementUI的效果:
实现思路
Step1:实现一个支持 v-model 的自定义输入组件
要实现的结果如下:保证 l-input 可以使用 v-model 来进行数据的双向绑定
v-model
:
- 原理:
- 把 inputValue 传给组件 l-input 内部
- 当组件 l-input 的 input 事件被触发时自动将事件携带的参数赋值给 inputValue
$event
:
当在父级组件监听事件的时候,我们可以通过 $event 访问到被抛出的值
代码
l-input 组件实现代码如下:
这个组件内的 必须:
- 将其 value 特性绑定到一个名叫 value 的 prop 上
- 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
export default {
props: {
value: {
type: String,
default: ''
},
type: {
type: String,
default: ''
}
},
methods: {
handlerInput(e) {
// 通知父组件值更新
this.$emit('input', e.target.value)
// 通知 formItem 进行校验
this.$parent.$emit('validate',e.target.value)
}
},
}
Step2:实现一个支持 负责label标签 以及 显示错误信息的组件
要实现的结果如下:保证 l-form-item 可以显示 label 以及可以对 prop 进行数据校验
代码
{{validateMsg}}
import schema from 'async-validator'
export default {
inject: ["form"], // 注入form 获取到 form 的 model 以及 rules
props: {
label: {
type: String,
default: ''
},
prop: {
type: String,
default: ''
}
},
data() {
return {
validateStatus: '',
validateMsg: ''
}
},
created() {
// 校测到来此 LInput 的检测请求
this.$on('validate', this.validate)
},
mounted() {
// 挂载到form上时,派发一个添加事件
// 如果此组件传入了 props ,则需要通知父组件 以放入检测数组
if (this.prop) {
this.$parent.$emit("formItemAdd", this)
}
},
methods: {
validate() {
// 使用 async-validator 进行校验
return new Promise((resolve) => {
console.log('validate -- input 通知我校验数据了', this.form.model[this.prop])
// 校验规则
let descriptor = {
[this.prop]: this.form.rules[this.prop]
}
// 校验器
let validator = new schema(descriptor)
// 开始校验数据
validator.validate({[this.prop]: this.form.model[this.prop]}, (error) => {
if(error) {
this.validateStatus = 'error'
this.validateMsg = error[0].message
resolve(false)
} else {
this.validateStatus = ''
this.validateMsg = ''
resolve(true)
}
})
})
}
},
}
Step3:实现一个支持 负责label标签 以及 显示错误信息的组件
要实现的结果如下:传入 表单数据对象(ruleForm) 和 表单验证规则(rules)后可以实现表单的数据校验 提供 validate 方法来获取整个表单的验证结果
// 传入的表单数据对象和表单验证规则
ruleForm: {
name: "",
pwd: ""
},
rules: {
name: [
{ required: true, message: "请输入名称" },
{ min: 6, max: 10, message: "请输入6~10位用户名" }
],
pwd: [{ required: true, message: "请输入密码" }]
}
// 调用组件的validate方法获取验证结果
this.$refs.loginForm.validate(valid => {
if (valid) {
alert("提交登录!")
} else {
console.log("校验失败")
return false
}
})
代码
export default {
provide() {
return {
form: this // 将表单实例传递给后代
}
},
props: {
model: {
type: Object,
required: true
},
rules: {
type: Object
}
},
data() {
return {
files: []
}
},
created() {
// 缓存需要校验的表单项
this.$on('formItemAdd', item => this.files.push(item))
console.log(this.files)
},
methods: {
// 将FormItem数组转换为 validate() 返回的promise数组
// 调用 LForm 组件的 validate 方法可以得到表单数据校验的结果
async validate(callback) {
let tasks = this.files.map(item => item.validate())
console.log(tasks)
// 获取所有结果统一处理
const results = await Promise.all(tasks)
let ret = true
results.forEach(valid => {
if (!valid) {
ret = false // 只要一个失败就失败
}
})
callback(ret)
}
},
}