Анализ исходного кода элемента из формы включает проверку таких компонентов, как ввод, выбор, флажок, средство выбора и радио. Проверка формы использует плагин async-validator. Давайте посмотрим вместе.
首先form表单组件由两部分组成
- форма: Единое управление формой-поз.
- form-item: отвечает за завершение проверки и т. д.
form
структура
<form class="el-form" :class="[
labelPosition ? 'el-form--label-' + labelPosition : '',
{ 'el-form--inline': inline }
]">
<slot></slot>
</form>
Структура очень проста, элемент формы оборачивает слот, который является элементом формы.
раздел сценария
1. Удобно ассоциировать с элементом формы и вводить экземпляр формы
// 注入组件实例
provide() {
return {
elForm: this
};
}
2. После создания экземпляра поля собирают экземпляр элемента формы.
created() {
// 监听el.form.addField事件,触发:将form-item实例push到fields
this.$on('el.form.addField', (field) => {
if (field) {
this.fields.push(field);
}
});
// 监听el.form.removeField事件,触发:form-item实例有prop规则属性从fields移除form-item实例
this.$on('el.form.removeField', (field) => {
if (field.prop) {
this.fields.splice(this.fields.indexOf(field), 1);
}
});
}
3. Некоторые методы проверки формы,form组件是做是统一管理具体执行还是在form-item中
-
Проверить всю форму
// 对整个表单进行验证 validate(callback) { // 没有表单数据 抛警告跳出 if (!this.model) { console.warn('[Element Warn][Form]model is required for validate to work!'); return; } let promise; // 没有callback并且浏览器支持Promise return promise if (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为空,调用验证时立刻返回callback if (this.fields.length === 0 && callback) { callback(true); } let invalidFields = {}; // 遍历所有实例,一个个验证 this.fields.forEach(field => { // 这里的validate是form-item的方法 field.validate('', (message, field) => { // 如果有返回信息, 则说明验证失败 if (message) { valid = false; } // 将错误对象复制到invalidFields invalidFields = objectAssign({}, invalidFields, field); // 调callback if (typeof callback === 'function' && ++count === this.fields.length) { callback(valid, invalidFields); } }); }); if (promise) { return promise; } }
Метод objectAssign находится в utils/merge, метод слияния объектов
-
Проверка некоторых форм
// 对部分表单验证 validateField(prop, cb) { let field = this.fields.filter(field => field.prop === prop)[0]; if (!field) { throw new Error('must call validateField with valid prop string!'); } // 验证对应表单规则的表单 field.validate('', cb); }
-
Удалить результат проверки элемента формы
传入待移除的表单项的 prop 属性组成的数组,如不传则移除整个表单的校验结果
clearValidate(props = []) { const fields = props.length ? this.fields.filter(field => props.indexOf(field.prop) > -1) : this.fields; fields.forEach(field => { // form-item实例的方法clearValidate(清除验证状态与提示) field.clearValidate(); }); }
-
Сбросить всю форму, сбросить все значения полей до начальных значений и удалить результаты проверки
resetFields() { // 没有表单数据 return if (!this.model) { // 环境变量,非生产环境抛警告再return process.env.NODE_ENV !== 'production' && console.warn('[Element Warn][Form]model is required for resetFields to work.'); return; } this.fields.forEach(field => { field.resetField(); }); }
4. Отслеживайте правила проверки
// 监听表单验证规则
watch: {
rules() {
// validateOnRuleChange未传入false则立即触发
if (this.validateOnRuleChange) {
// 验证
this.validate(() => {});
}
}
}
form-item
структура
<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
},
sizeClass ? 'el-form-item--' + sizeClass : ''
]">
<!-- 表单域标签文本 -->
<label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
<slot name="label">{{label + form.labelSuffix}}</slot>
</label>
<div class="el-form-item__content" :style="contentStyle">
<!-- 插槽接收表单验证的元素,input框单选框多选框之类的 -->
<slot></slot>
<!-- 验证不通过时的message -->
<transition name="el-zoom-in-top">
<div
v-if="validateState === 'error' && showMessage && form.showMessage"
class="el-form-item__error"
:class="{
'el-form-item__error--inline': typeof inlineMessage === 'boolean'
? inlineMessage
: (elForm && elForm.inlineMessage || false)
}"
>
{{validateMessage}}
</div>
</transition>
</div>
</div>
Внешний блок управляет общим стилем, а внутренний разделён на две части.
- Первая часть: может отображать метку или объединяющий унифицированный суффикс (атрибут from)
- Вторая часть: слот получает такие компоненты, как ввод, выбор и отображение сообщения при сбое проверки.
这里的变量elForm就是form组件provide的from实例
раздел сценария
1.Inject получает экземпляры форм и вводит экземпляры элементов формы потомкам.
provide() { // 注入form-item实例
return {
elFormItem: this
};
},
// 接收form实例
inject: ['elForm']
2. После подключения компонента $el к экземпляру
Для инициализации собираются компоненты формы, которые необходимо проверить, и отслеживаются события el.form.blur и el.form.change с правилами проверки, ожидая запуска проверки.
mounted() {
// 有需要验证的表单
if (this.prop) {
// 向上查找form组件,并发布el.form.addField,暴露form-item实例
// 即让form组件收集需要验证的form-item实例
this.dispatch('ElForm', 'el.form.addField', [this]);
// 需要验证的表单数据
let initialValue = this.fieldValue;
// 是数组
if (Array.isArray(initialValue)) {
initialValue = [].concat(initialValue);
}
// 响应属性变成普通属性
Object.defineProperty(this, 'initialValue', {
value: initialValue
});
// 该项验证规则
let rules = this.getRules();
if (rules.length || this.required !== undefined) {
// 监听el.form.blur,回调为bluer事件验证
// 监听el.form.change事件,回调为change事件验证
this.$on('el.form.blur', this.onFieldBlur);
this.$on('el.form.change', this.onFieldChange);
}
}
}
- Используемый здесь метод отправки представлен из миксинов: найти указанный компонент и опубликовать указанное событие.
3. Метод проверки
validate(trigger, callback = noop) {
this.validateDisabled = false;
// 符合规则的trigger
const rules = this.getFilteredRule(trigger);
// 没有规则也不是必填 返回true
if ((!rules || rules.length === 0) && this.required === undefined) {
// 执行回调
callback();
return true;
}
// 验证中
this.validateState = 'validating';
const descriptor = {};
// 为了匹配AsyncValidator插件所需要的格式,需要做规则数据做一些操作
if (rules && rules.length > 0) {
rules.forEach(rule => {
delete rule.trigger;
});
}
// AsyncValidator需要的验证规则
descriptor[this.prop] = rules;
// 验证规则AsyncValidator实例对象
const validator = new AsyncValidator(descriptor);
const model = {};
// AsyncValidator需要的验证数据
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);
});
}
4. Очистите статус проверки и сбросьте метод проверки формы.
// 清空验证状态及message
clearValidate() {
// 验证状态
this.validateState = '';
// 验证message
this.validateMessage = '';
this.validateDisabled = false;
},
// 重置
resetField() {
this.validateState = '';
this.validateMessage = '';
// 拿到初始数据
let model = this.form.model;// 所以表单数据
let value = this.fieldValue; // 该项表单数据
let path = this.prop; //该项
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
// 该项表单数据
let prop = getPropByPath(model, path, true);
this.validateDisabled = true;
// 重置为初始表单数据
if (Array.isArray(value)) {
prop.o[prop.k] = [].concat(this.initialValue);
} else {
prop.o[prop.k] = this.initialValue;
}
// 向下寻找select组件,发布fieldReset事件暴露初始表单数据
this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue);
}
5. Отслеживайте ошибки и проверяйте статус
Ошибка здесь принимается реквизитами: если она передается, статус меняется на ошибка, и отображается сообщение об ошибке.
watch: {
// 监听error
error: {
// 立即执行handler
immediate: true,
handler(value) {
// 验证状态变为error,并显示错误信息
this.validateMessage = value;
this.validateState = value ? 'error' : '';
}
},
// 监听验证状态
validateStatus(value) {
this.validateState = value;
}
}
6. Перед уничтожением экземпляра опубликуйте форму, чтобы удалить собранный экземпляр элемента формы.
beforeDestroy() {
// 向上寻找form组件,发布el.form.removeField事件,暴露当前实例
this.dispatch('ElForm', 'el.form.removeField', [this]);
}
Связь между компонентами формы и такими компонентами, как ввод
是怎么触发from验证的呢
Форма прослушивает события el.form.blur и el.form.change при монтировании и указывает функцию обратного вызова проверки.
this.$on('el.form.blur', this.onFieldBlur);
this.$on('el.form.change', this.onFieldChange);
Взять ввод в качестве примера
// form表单发布el.form.blur事件
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]);
В качестве примера возьмем множественный выбор флажка
// 监听value 向上寻找form组件发布el.form.change事件暴露value(数组)
this.dispatch('ElFormItem', 'el.form.change', [value]);
подождите... , эти тайминги запускают проверку
$on
Это прослушивание указанного события и указание функции обратного вызова,$emit
Опубликовать событие и передать некоторые данные (или нет), когда имя отслеживаемого события совпадает с именем опубликованного события, будет запущена отслеживаемая функция обратного вызова, а параметр будет соответствующим$emit
переданные параметры.
Метод прямого экземпляра официального сайта$on
так же как$emit