vuetify vee-validate 滚动到第一个验证错误

vuetify vee-validate scroll to the first validation error

如果在表单中单击提交按钮,如果存在错误,它应该会自动滚动到第一个验证错误。 我读过我可以为此使用 "scrolltoview",但我不知道具体如何。

我已经尝试过使用简单的 ScrollTo (0.0) 来在出现错误时简单地向上滚动,并且效果很好。 然而,这不是我想要的解决方案。

< script >
  ...
  let name = 'm-form-user';
export default {
  name: name,
  mixins: [baseForm],
  props: {
    name: {
      type: String,
      default: name
    },
    title: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'create',
      validator: function(value) {
        return ['edit', 'create'].indexOf(value) !== -1
      }
    },
  },
  data: () => ({
    form: {
      firstName: '',
      lastName: '',
      position: '',
      email: '',
      mobile: '',
      roles: []
    }
  }),
  async created() {
    if (!this.isCreationForm && this.$route.params.id) {
      if (!this.editingUser.length) {
        await this.requestUser({
          id: this.$route.params.id
        });
      }
      Object.assign(this.form, this.editingUser);
      this.form.roles.pop()
    }
  },
  computed: {
    ...mapGetters({
      getUser: "users/read"
    }),

    text() {
      return {
        cancel: this.$t('modules.forms.m-form-user.buttons.cancel'),
        submit: this.$t('modules.forms.m-form-user.buttons.submit')
      }
    },

    editingUser() {
      return this.getUser(this.$route.params.id)
    },
    isCreationForm() {
      return this.type === 'create'
    }
  },
  methods: {
    ...mapActions({
      requestCreateUser: 'users/create',
      requestUpdateUser: 'users/update',
      requestUser: 'users/read'
    }),
    async submit() {
      const validAll = await this.$validator.validateAll();
      const validIdentify = this.validateIdentify();

      if (!validAll || !validIdentify) {


        // ScrolltoView

        return;
      }


      try {
        this.setOrganizationRelation();
        let user = this.isCreationForm ? await this.createUser() : await this.updateUser();
        this.notify.success(this.$t(`notifications.account.userManagement.${ this.isCreationForm ? 'created':'edited'}`, {
          firstName: user.firstName,
          lastName: user.lastName
        }))
        this.redirect(this.nav.dashboard.account.users.view.name, {
          id: user._id
        })
      } catch (e) {
        if (e.response && e.response.status === 400) {
          e.response.data.violations.forEach(violation => {
            if (violation.propertyPath === 'username') return; //TODO temporary workaround, remove it when we get correct response from server
            this.$validator.errors.add({
              id: violation.propertyPath,
              field: violation.propertyPath,
              msg: violation.message
            });


            const field = this.$validator.fields.find({
              name: violation.propertyPath
            });

            if (!field) {
              throw `Field "${violation.propertyPath}" in "${this.$options._componentTag}" component don't have validation on client side!`;
            }

            field.setFlags({
              invalid: true,
              valid: false,
              validated: true
            });
          });
        } else {
          this.notify.processUnhandledError(e);
        }
      }

    },
    async createUser() {
      return await this.requestCreateUser({ ...this.form,
        password: passwordGenerator.generate()
      });
    },
    async updateUser() {
      return await this.requestUpdateUser(this.form)
    },
    cancel() {
      this.goBack();
    },

    validateIdentify() {
      if (!this.form.email && !this.form.mobile) {
        const fields = (({
          email,
          mobile
        }) => ({
          email,
          mobile
        }))(this.$refs);
        Object.keys(fields).forEach((key) => {
          let field = this.$validator.fields.find({
            name: fields[key].name
          });

          this.$validator.errors.add({
            id: field.id,
            field: field.name,
            msg: this.$t('modules.forms.m-form-user.sections.contacts.emptyContacts')
          });

          field.setFlags({
            invalid: true,
            valid: false,
            validated: true
          });

          this.$refs.emailBlock.open();
          this.$refs.mobileBlock.open();
        });
        return false;
      }
      return true;
    },
    setOrganizationRelation() {
      const rel = {
        organization: this.$user.relationships.organization
      };
      setRelations(this.form, rel)
    }
  }
} <
/script>
<m-block-form-fields :required="false">
  <template #title>
                    {{$t('modules.forms.m-form-user.sections.personal.title')}}
                </template>

  <template>
                    <v-layout wrap>
                        <v-flex xs12>
                            <e-input-user-name v-model="form.firstName" rules="required" required-style/>
                        </v-flex>
                        <v-flex xs12>
                            <e-input-user-surname v-model="form.lastName" rules="required" required-style/>
                        </v-flex>
                        <v-flex xs12>
                            <e-input-user-position-function v-model="form.position"/>
                        </v-flex>
                    </v-layout>
                </template>
</m-block-form-fields>

尝试使用 document.querySelector 找到第一条错误消息,如下所示。

      if (!validAll || !validIdentify) {
        const el = document.querySelector(".v-messages.error--text:first-of-type");
        el.scrollIntoView();
        return;
      }

这是基于@Eldar 的回答。

因为您要更改 DOM,所以您只想在 DOM 更新后查找新元素。

我能够使它与 nextTick 一起使用。

if(!validAll || !validIdentify) {
    // Run after the next update cycle
    this.$nextTick(() => {
        const el = this.$el.querySelector(".v-messages.error--text:first-of-type");
        this.$vuetify.goTo(el);
        return;
    });
}