基本用法
Element-UI 入门
- 初始化项目并安装 ElementUI
# 初始化项目
vue create element-test
# 切换目录运行
cd element-test
npm run serve
# 安装element-ui
npm i element-ui -S
- 全局引入
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'Vue.use(ElementUI)
- 按需引入
参考官网做法即可:按需引入
# 项目打包
npm run build
# 查看dist js文件大小 1.1M左右
ll dist/js
# -rw-r--r-- 1 xxx 197609 118697 9月 27 11:10 chunk-vendors.123827f3.js
- 插件引用
vue add element
表单基本用法
el-form
容器,通过v-model
绑定数据el-form-item
容器,通过label
绑定标签- 表单组件通过
v-model
绑定model
中的数据
<template><div id="app"><el-form inline :model="data"><el-form-item label="审批人"><el-input v-model="data.user" placeholder="审批人"></el-input></el-form-item><el-form-item label="活动区域"><el-select v-model="data.region" placeholder="活动区域"><el-option label="区域一" value="shanghai"></el-option><el-option label="区域二" value="beijing"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">查询</el-button></el-form-item></el-form></div>
</template><script>
export default {name: 'app',data() {return {data: {user: '',region: '区域二'}}},methods: {onSubmit() {console.log(this.data)}}
}
</script>
表单校验用法
基础用法
- 定义校验规则
data() {const userValidator = (rule, value, callback) => {if (value.length > 3) {callback()} else {callback(new Error('用户名长度必须大于3'))}}return {data: {user: 'sam',region: '区域二'},rules: {user: [{ required: true, trigger: 'change', message: '用户名必须录入' },{ validator: userValidator, trigger: 'change' }]}}
},
methods: {onSubmit() {this.$refs.form.validate((isValid, errors) => {console.log(isValid, errors)})}
}
- 指定
el-form-item
的prop
属性(在使用validate
、resetFields
方法的情况下,该属性必填)
<el-form inline :model="data" :rules="rules" ref="form"><el-form-item label="审批人" prop="user"><el-input v-model="data.user" placeholder="审批人" clearable></el-input></el-form-item>
</el-form>
动态添加校验规则
rules
删除一个校验规则,现在只包含一个校验规则
data() {return {data: {user: '',region: '',},rules: {user: [{ required: true, trigger: 'change', message: '用户名必须录入' }],},}
},
- 动态添加
rules
表单中添加新的校验规则会立即进行校验,是因为这个属性
validate-on-rule-change
默认为 true,改为 false 即可<el-form inline :model="data" :rules="rules" ref="form" validate-on-rule-change="false">
addRule() {const userValidator = (rule, value, callback) => {if (value.length > 3) {/* this.inputError = ''this.inputValidateStatus = '' */callback()} else {callback(new Error('用户名长度必须大于3'))}}const newRule = [...this.rules.user, { validator: userValidator, trigger: 'change' }]this.rules = Object.assign({}, this.rules, { user: newRule })
},
注意:新增新规则必须重新生成一个新的 rules
对象,因为 watch
只能监听 rules
,而监听不到内部的变化
- 使用
this.rules = Object.assign({}. this.rules, { user: newRule })
- 不能使用
this.rules.user.push(newRule)
手动控制校验状态
- validate-status:验证状态,枚举值,共四种:
- success:验证成功
- error:验证失败
- validating:验证中
- (空):未验证
- error:自定义错误提示
- 在
data
中新增error
和status
变量 - 设置
status-icon
属性<el-form inline :model="data" :rules="rules" ref="form" validate-on-rule-change="false" status-icon>
- 设置
el-form-item
属性<el-form-item label="审批人" prop="user" :error="error" :validate-status="status">
- 新增按钮
<el-button type="success" @click="showSuccess">校验成功</el-button> <el-button type="danger" @click="showError">校验失败</el-button> <el-button type="warning" @click="showValidating">校验中</el-button>
- 在
methods
中定义status
和error
的方法showError() {this.status = 'error'this.error = '用户名输入有误' }, showSuccess() {this.status = 'success'this.error = '' }, showValidating() {this.status = 'validating'this.error = '' },
表单属性
label-position
:标签位置left
、right
、top
。如果设置为left
、right
则需要设置label-width
label-width
:标签宽度label-suffix
:标签后缀,一般会设置个冒号:
inline
:行内表单disabled
:设置整个form
的表单组件全部disabled
,优先级低于表单组件自身的disabled
status-icon
:输入框右侧显示校验反馈图标validate-on-rule-change
:是否在rules
属性改变后立即触发一次验证
disbabled
- 直接看
element-ui\packages\form\src\form.vue
看里面是没有对
disabled
进行处理,而是用provide
将自身传递给了后代
provide() {return {elForm: this};
},
- 之后去看
element-ui\packages\input\src\input.vue
找到
:disabled="inputDisabled"
,这里先判断自身是否有disabled
属性,再判断祖先是否含有(自身的优先级高一些)。这里使用了inject
去接收elForm
和elFormItem
inject: {elForm: {default: ''},elFormItem: {default: ''}
},
computed: {inputDisabled() {return this.disabled || (this.elForm || {}).disabled;},
}
size
- 先去看
element-ui\packages\input\src\input.vue
找到
inputSize ? 'el-input--' + inputSize : '',
,会先找到_elFormItemSize
,之后会去找elFormItem
里的 elFormItemSize
computed: {_elFormItemSize() {return (this.elFormItem || {}).elFormItemSize;},inputSize() {return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;},
}
- 之后去看
element-ui\packages\form\src\form-item.vue
它也是通过
provide
将自身传递给后代
provide() {return {elFormItem: this};
},
这里去找 elFormItemSize
,最后发现它是直接找 this.elForm.size
computed: {_formSize() {return this.elForm.size;},elFormItemSize() {return this.size || this._formSize;},
}
ElementUI form 源码
入口
element-ui\src\index.js
是 ElementUI 的入口文件
Vue.use(Element)
调用 ElementUI 入口的install
方法,会加载全部组件所有组件在存在
components
数组中
const install = function(Vue, opts = {}) {components.forEach(component => {Vue.component(component.name, component);});// 全局引入时不需要写这些Vue.prototype.$loading = Loading.service;Vue.prototype.$msgbox = MessageBox;Vue.prototype.$alert = MessageBox.alert;Vue.prototype.$confirm = MessageBox.confirm;Vue.prototype.$prompt = MessageBox.prompt;Vue.prototype.$notify = Notification;Vue.prototype.$message = Message;
};
按需加载相当于手动调用 Vue.component(xxx.name, xxx)
from.vue
el-form
中容器功能是通过插槽来实现的,自身属性只有两个 labelPosition
、inline
,其余全部向下传递
<template><form class="el-form" :class="[labelPosition ? 'el-form--label-' + labelPosition : '',{ 'el-form--inline': inline }]"><slot></slot></form>
</template>
watch
主要监听 rules
的变化,对 rules
进行变更会去判断 validateOnRuleChange
是否启用,启用则执行一次
watch: {rules() {// remove then add event listeners on form-item after form rules changethis.fields.forEach(field => {field.removeValidateEvents();field.addValidateEvents();});if (this.validateOnRuleChange) {this.validate(() => {});}}
},
from
里的validate
对整个表单进行验证
validate(callback) {// 判断有没有表单数据if (!this.model) {console.warn('[Element Warn][Form]model is required for validate to work!');return;}let promise;// if no callback, return promiseif (typeof callback !== 'function' && window.Promise) {promise = new window.Promise((resolve, reject) => {callback = function(valid) {valid ? resolve(valid) : reject(valid);};});}let valid = true;let count = 0;// 如果需要验证的fields为空,调用验证时立刻返回callbackif (this.fields.length === 0 && callback) {callback(true);}let invalidFields = {};// 依次遍历所有field,一个一个验证this.fields.forEach(field => {// 执行form-item里的validate方法field.validate('', (message, field) => {if (message) {valid = false;}invalidFields = objectAssign({}, invalidFields, field);// 如果有错误会调用callbackif (typeof callback === 'function' && ++count === this.fields.length) {callback(valid, invalidFields);}});});if (promise) {return promise;}
},
form-item.vue
is-no-asterisk
->hide-required-asterisk
是否隐藏必填字段的标签旁边的红色星号
<template><div class="el-form-item" :class="[{'el-form-item--feedback': elForm && elForm.statusIcon,'is-error': validateState === 'error','is-validating': validateState === 'validating','is-success': validateState === 'success','is-required': isRequired || required,'is-no-asterisk': elForm && elForm.hideRequiredAsterisk},sizeClass ? 'el-form-item--' + sizeClass : '']"><label-wrap:is-auto-width="labelStyle && labelStyle.width === 'auto'":update-all="form.labelWidth === 'auto'"><label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label"><slot name="label">{{label + form.labelSuffix}}</slot></label></label-wrap><div class="el-form-item__content" :style="contentStyle"><slot></slot><transition name="el-zoom-in-top"><slotv-if="validateState === 'error' && showMessage && form.showMessage"name="error":error="validateMessage"><divclass="el-form-item__error":class="{'el-form-item__error--inline': typeof inlineMessage === 'boolean'? inlineMessage: (elForm && elForm.inlineMessage || false)}">{{validateMessage}}</div></slot></transition></div></div>
</template>
当表单验证有误时,文字出现是有动画的,使用的是 Vue 的 transition
组件的动画
transition
组件里面有个slot
插槽(具名插槽name="error"
),这里允许我们自己对错误提示文本的样式进行自定义修改
$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;.el-zoom-in-top-enter-active,
.el-zoom-in-top-leave-active {opacity: 1;transform: scaleY(1);transition: $--md-fade-transition;transform-origin: center top;
}
.el-zoom-in-top-enter,
.el-zoom-in-top-leave-active {opacity: 0;transform: scaleY(0);
}
- 之前自定义
error
,它会立即展示出来效果(在created
会执行一次)
watch: {error: {immediate: true,handler(value) {this.validateMessage = value;this.validateState = value ? 'error' : '';}},validateStatus(value) {this.validateState = value;}
},
from-item
里的validate
对每一项进行验证
validate(trigger, callback = noop) {this.validateDisabled = false;const rules = this.getFilteredRule(trigger);// 没有验证规则,直接返回trueif ((!rules || rules.length === 0) && this.required === undefined) {callback();return true;}// 状态改为验证中this.validateState = 'validating';const descriptor = {};// 匹配async-validator第三方库需要的格式,做的处理if (rules && rules.length > 0) {rules.forEach(rule => {delete rule.trigger;});}descriptor[this.prop] = rules;// 对rulues进行验证,使用async-validator第三方库const validator = new AsyncValidator(descriptor);const model = {};// async-validator需要验证的数据model[this.prop] = this.fieldValue;// 验证validator.validate(model, { firstFields: true }, (errors, invalidFields) => {this.validateState = !errors ? 'success' : 'error';this.validateMessage = errors ? errors[0].message : '';// 执行回调callback(this.validateMessage, invalidFields);// form组件发布validate事件this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null);});
},
async-validator
Element 表单校验主要使用了 async-validator 这个库
这个插件基本流程如下:
- 按照
rule
的规则生成rules
,并指定每个字段的规范 - 根据
rules
生成验证器const validator = new Validator(rules)
- 对验证器进行验证
validator.validate(source, [options], callback)
- 匹配
source
中的字段对应规则,全部通过或出错调用callback
import Validator from 'async-validator'// 规则描述
const rules = {name: { type: 'string', require: true },
}
// 根据规则生成验证器
const validator = new Validator(rules)
// 要验证的数据源
const source = {name: 'bird',
}
// 验证后的回调函数
function callBack(errors, fields) {if (errors) {// 验证不通过,errors是一个数组,记录那些不通过的错误信息// fields 是所有数据源的字段名,即source中的name}// 验证通过后的逻辑
}
// 验证数据源是否符合规则(如果验证时有一个不通过,终止验证下个规则[一个字段多个规则情况])
validator.validate(source, { firstFields: true }, callBack)
Rules
- 函数方式:
{ name(rule, value, callback, sources, options) }
- 对象方式:
{ name: { type: 'string', required: true } }
- 数组方式:
{ name: [{ type: 'string' }, { required: true }] }
Rules 默认规则
type
:要验证的数据类型string
:必须是 String 类型number
:必须是 Number 类型boolean
:必须是 Boolean 类型method
:必须是 Function 类型regexp
:必须是 RegExp 类型array
:必须是 Array.isArray 通过的数组object
:必须是 Array.isArray 不通过的类型的 Object 类型date
:必须是 Date 对象的实例integer
:必须是 Number 类型的正整数float
:必须是 Number 类型的浮点数enum
:预先定义 enum,值必须是 enum 某个值url
:必须符合链接格式hex
:必须是 16 进制email
:必须符合邮件格式any
:任意数据类型
required
:是否必填pattern
:使用正则来验证pattern: '[^ \x22]+'
(前后空格不匹配)min
:数据长度的最小值(数据类型必须是string
、array
)max
:数据长度的最大值(数据类型必须是string
、array
)len
:数据长度必须等于这个值(数据类型必须是string
、array
)enum
:数据的值必须等于这个枚举数组中的某个元素transform
:钩子函数,在开始验证之前对数据预先处理transform(value) { return value.trim() }
message
:报错提示信息,可以是字符串或标签message: () => this.$t('name')
(不过这种变化不是实时的,想要实时的需要放在 computed 里面)validator
:自定义验证函数以及报错信息validator(rule, value, callback)
- deep rules 深度验证处理 object 或 array 类型,使用
fields
或defaultField
const url = ['http://www.xx.com', 'http://www.xx.cn'] const rules1 = {urls: {type: 'array',require: true,defaultField: { type: url },}, }const obj = {name: 'bird',age: 12,addr: 'xxx', } const rules2 = {ids: {type: 'object',require: true,fields: {name: { type: 'string', require: true },age: { type: 'number', require: true, transform: Number },addr: { type: 'string', require: true },},}, }