iView 是TalkingData 基于 Vue.js 开发的一套高质量 UI 组件库 ,其包含了工程构建、主题定制、多语言等功能,极大提升了我们在开发项目时的工作效率,几个项目下来感觉还是挺好用的,值得安利和深入研究,接下来我们 研究一下其源码,以此来加深对框架的了解。
Form组件结构
通过查看iview源码得知, 一个完整的Form表单主要由Form、 FormItem 主一些表单空件按钮等组成。
--node_modules/iview/src/components/
--form.vue
--form-item.vue
--index.js
其中 :
Form 主要是对form做一层封装
FormItem 是一个容器,主要用来存放一些表单控件和 标签,提示消息等内容。
源码分析
通常来说,在构建一个form组件时一般都围绕以下几个核心功能展开:
收集用户录入的一些数据
录入数据校验(自定义校验规则和提示)
表单提交校验
iview Form亦是如此,具体如下所示
1.form.vue
//-其实就是为了方便使用Vue.use去初始化这个框架(可以认为是插件,通过install集中管理拆分的组件,
//提高iview的可拓展性)
import Form from './form.vue';
import FormItem from './form-item.vue';
Form.Item = FormItem;
export default Form;
//form.vue
<template>
<form :class="classes" :autocomplete="autocomplete"><slot></slot></form>
</template>
<script>
import { oneOf } from '../../utils/assist'; //工具类
const prefixCls = 'ivu-form'; //组件dom前缀
export default {
name: 'iForm',
props: {
model: {
type: Object //表单数据对象
},
rules: {
type: Object //表单数据对象
},
labelWidth: {
type: Number // 表单域标签的宽度,所有的 FormItem 都会继承 Form 组件的 label-width 的值
labelPosition: {
//表单域标签的位置,validator是prop中用来校验传入值的自定义函数,返回值boolean
validator (value) {
return oneOf(value, ['left', 'right', 'top']);
default: 'right'
},
inline: {
//是否开启行内表单模式
type: Boolean,
default: false
},
showMessage: {
//是否显示校验错误信息
type: Boolean,
default: true
},
autocomplete: {
//原生的 autocomplete 属性
validator (value) {
return oneOf(value, ['on', 'off']);
},
default: 'off'
}
},
provide() {
//provide 可以理解为组件中的一个全局变量,在此处定义的变量 可以供子组件中通过inject使用
return { form : this };
},
data () {
return {
fields: []
};
},
computed: {
classes () {
//动态设置表单域标签的位置
return [
`${prefixCls}`,
`${prefixCls}-label-${this.labelPosition}`,
{
[`${prefixCls}-inline`]: this.inline
}
];
}
},
methods: {
//表单重置 即reset
resetFields() {
this.fields.forEach(field => {
field.resetField();
});
},
//表单全局校验,注意返回的是个promise,并没有执行
//this.$refs["xxxForm"].validate(valid => {})
validate(callback) {
return new Promise(resolve => {
let valid = true;
let count = 0;
this.fields.forEach(field => {
field.validate('', errors => {
if (errors) {
valid = false;
}
if (++count === this.fields.length) {
// all finish
resolve(valid);
if (typeof callback ===