vue+element自定义组件如何触发element表单验证

·  阅读 2782

前端小伙伴们在做项目时或多或少都接触过表单,表单最重要的一环就是表单验证,不知道大家考虑过这个问题没有,当使用自己开发的组件时如何触发表单验证提示呢?

我之前做过一个功能,使用的是yamlEditor组件,由于项目(技术栈:vue+element)紧急,当时剑走偏锋,在form-item里同时写了个textarea,与ymalEditor绑定同一个值,这样就能触发form的验证了,具体代码如下:

<el-form-item
  :label="$t('label.emsRelease.compose')"
  prop="compose"
  class="check-box__form-item"
  v-if="taskTemplateInfo.taskArgs.deployType == COMPOSE_DEPLOY"
>
  <!-- do not delete the code behind -->
  <el-input
    type="textarea"
    :placeholder="$t('placeholder.emsRelease.compose')"
    v-model="taskTemplateInfo.taskArgs.compose"
    name="compose"
    style="position: absolute; z-index: -100"
  ></el-input>
  <yamlEditor
    v-model="taskTemplateInfo.taskArgs.compose"
    style="width: 400px"
  />
</el-form-item>
复制代码

后来想想此做法并没有从根源是解决问题,因此,我又到element源码里偷学了,看了一下几个文件

1、node_modules/element-ui/packages/input/src/input.vue

handleBlur(event) {
    this.focused = false;
    this.$emit('blur', event);
    if (this.validateEvent) {
        this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
    }
},

value(val) {
    this.$nextTick(this.resizeTextarea);
    if (this.validateEvent) {
        this.dispatch('ElFormItem', 'el.form.change', [val]);
    }
},


this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
this.dispatch('ElFormItem', 'el.form.change', [val]);
复制代码

这两代码看起来有点熟悉,然后我就去看了一下dispatch方法。

2、node_modules/element-ui/src/mixins/emitter.js

dispatch(componentName, eventName, params) {
  var parent = this.$parent || this.$root;
  var name = parent.$options.componentName;

  while (parent && (!name || name !== componentName)) {
    parent = parent.$parent;

    if (parent) {
      name = parent.$options.componentName;
    }
  }
  if (parent) {
    parent.$emit.apply(parent, [eventName].concat(params));
  }
},
复制代码

这是触发父组件里的某个方法用的,然后我就去寻踪追影,查看form-item的代码

3、node_modules/element-ui/packages/form/src/form-item.vue

addValidateEvents() {
  const rules = this.getRules();

  if (rules.length || this.required !== undefined) {
    this.$on('el.form.blur', this.onFieldBlur);
    this.$on('el.form.change', this.onFieldChange);
  }
},

onFieldBlur() {
  this.validate('blur');
},
onFieldChange() {
  if (this.validateDisabled) {
    this.validateDisabled = false;
    return;
  }
  this.validate('change');
},

validate(trigger, callback = noop) {
  this.validateDisabled = false;
  const rules = this.getFilteredRule(trigger);
  if ((!rules || rules.length === 0) && this.required === undefined) {
    callback();
    return true;
  }

  this.validateState = 'validating';

  const descriptor = {};
  if (rules && rules.length > 0) {
    rules.forEach(rule => {
      delete rule.trigger;
    });
  }
  descriptor[this.prop] = rules;

  const validator = new AsyncValidator(descriptor);
  const model = {};

  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);
    this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null);
  });
}
复制代码

这里大概就是在form-item中绑定了el.form.blur和el.form.change两个方法,在触发这两个方法时会执行validate方法,然后完成验证。

到这里我就大概知道该怎么改造自己的组件了,我组件里加了两个方法,如下图:

dispatch(componentName, eventName, params) {
  var parent = this.$parent || this.$root;
  var name = parent.$options.componentName;

  while (parent && (!name || name !== componentName)) {
    parent = parent.$parent;

    if (parent) {
      name = parent.$options.componentName;
    }
  }
  if (parent) {
    parent.$emit.apply(parent, [eventName].concat(params));
  }
},

//在触发change的地方增加dispatch
checkValue() {
  this.$emit("change", this.checkValue);
  this.dispatch("ElFormItem", "el.form.change", [this.checkValue]);
},
复制代码

如果自定义组件可以触发blur事件的话还可以加上

this.dispatch('ElFormItem', 'el.form.blur', [this.checkValue]);
复制代码

当然样式上也要做下修改,在校验不通过时添加样式,示例如下:

//less
.el-form-item.is-error { 
  //添加自己的样式
  .ci-emp-dropdown {
    ci-dropdown__link {
      border-color: #ec4c47;
    }
  }
}
复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改