Vue-component | 自定义Form组件
2020-03-16 本文已影响0人
鱼太咸丶
日常开发中积累了不少可能对一些开发有帮助的简单易用的组件,好记性不如烂笔头,想对过去的一些零零乱乱的东西做一些总结,反省自己的同时也便于思考一些更优的方法,提升下开发思维😉😉😉。
代码传送门(😃感觉有作用的的同学帮忙点下❤️️)
效果截图
先上效果图,自定义规则,违反规则马上显示提示。
Form
组件结构
参照elementUI的表单组件,组件的结构是Form > ... (FormItem > Form组件)
<j-form> // Form
<j-form-item> // FormItem
<j-input></j-input> // content
</j-form-item>
// ...可以添加多个Item
</j-form>
核心代码
Form组件
最上级是Form组件,是进行全局验证的组件,并且接收prop
(传递的数据模型和规则),并将自身注入到子级中。
<template>
<div id="form">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'j-form',
// 将自身注入
provide () {
return {
form: this
}
},
props: {
// 数据模型
model: {
type: Object,
required: true
},
// 校验规则
rules: {
type: Object
}
},
methods: {
// 表单全局校验方法,校验所有的item内容
validate (callBack) {
const tasks = this.$children.filter(item => item.prop).map(item => item.validate())
// 所有任务都通过才算校验通过
Promise.all(tasks).then(() => callBack(true)
).catch(() => callBack(false)
)
}
}
}
</script>
FormItem组件
用item组件包裹表达内容组件,目的是为了进行单一校验,并产生错误的提示信息。这里使用的是async-validator
第三方的校验库,需要额外装载。
<template>
<div id="form-item">
<label v-if="label" class="label">{{label}}</label>
<slot></slot>
<p v-if="errorMsg" class="error-msg">{{errorMsg}}</p>
</div>
</template>
<script>
import Schema from 'async-validator'
export default {
name: 'j-form-item',
components: {},
inject: ['form'],
data () {
return {
errorMsg: ''
}
},
props: {
// 标题文本
label: {
type: String,
default: '',
required: true
},
// 数据字段名
prop: {
type: String
}
},
mounted () {
// 监听校验
this.$on('validate', () => { this.validate() })
},
methods: {
validate () {
console.log('触发校验===')
// async-validator的校验方法
const value = this.form.model[this.prop]
const rules = this.form.rules[this.prop]
const desc = { [this.prop]: rules }
const schema = new Schema(desc)
// return的是校验结果的Promise
return schema.validate({ [this.prop]: value }, errors => {
if (errors) {
console.log('error', errors[0].message)
this.errorMsg = errors[0].message
} else {
console.log('error', errors)
this.errorMsg = ''
}
})
}
}
}
</script>
Input组件
内容组件,在这里进行内容的监听,上到FormItem进行校验
<template>
<div id="input">
<input :value="value" @input="onInput" v-bind="$attrs" />
</div>
</template>
<script>
export default {
name: 'j-input',
// 禁用继承的属性
inheritAttrs: false,
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: ''
}
},
methods: {
onInput (e) {
console.log(e.target.value)
// 监听数值变化
this.$emit('change', e.target.value)
// 触发校验
this.$parent.$emit('validate')
}
}
}
</script>
使用
使用组件就和elementUI一样进行处理即可
<template>
<div id="home">
<j-form ref="ruleForm" :model="model" :rules="rules">
<j-form-item label="姓名" prop="name">
<j-input v-model="model.name" placeholder="请输入姓名" />
</j-form-item>
<j-form-item label="年龄" prop="age">
<j-input v-model="model.age" placeholder="请输入年龄" />
</j-form-item>
</j-form>
</div>
</template>
<script>
export default {
components: {},
data () {
return {
model: {
name: '',
age: ''
},
rules: {
name: [
{ required: true, message: '请填写姓名', trigger: 'change' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'change' }
],
age: [
{ required: true, message: '请填写年龄', trigger: 'change' },
{ min: 1, max: 2, message: '长度在 1 到 2 个字符', trigger: 'change' }
]
}
}
}
关键点
处理自定义组件,一定要对vue中的传值比较清晰了解,这里就不一一列举。在这里主要使用的一些技术包括:
技术 | 概述 | 备注 |
---|---|---|
props传值 | 父级传子级 | / |
provide-inject | 从上往下可以跨级传值 | 在代码里将自身传递下来 |
slot | 插槽,将子组件插入父组件中 | Input>FormIten>Form |
inheritAttrs-$attrs | 禁用继承的属性直接赋予给根标签,自定义继承 | / |
v-model | 自定义双向传值 | / |
Promise.all() | 同时完成所有的任务 | / |
后续会持续更新其他一些有用的组件提供参考...