首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用VeeValidate验证由按钮组成的自定义选择组件?

如何使用VeeValidate验证由按钮组成的自定义选择组件?
EN

Stack Overflow用户
提问于 2021-03-09 21:15:24
回答 1查看 732关注 0票数 0

我正在尝试构建一个自定义的select输入,功能可以正常工作,但不能用于验证。因为<button>不能有v-model,所以我不能通过下面的例子让它工作。我不认为我可以使用计算属性方法like shown in the docs,因为我只使用计算属性来获取要在UI中显示的选定值的文本,而不是发送到父级,也不是设置值。

<li>元素上使用@click="$emit(...)"来设置这些值。

为了清楚起见,我在这里提供了脚本和实现,请看一下

BaseSelect.vue

代码语言:javascript
复制
<template>
  <ValidationProvider
    tag="div"
    :vid="name"
    :mode="validationMode"
    :rules="validationRules"
    v-slot="{ errors }"
  >
    <label :id="name" class="block font-medium mx-2 mb-3">{{ label }}</label>
    <div class="relative">
      <button
        type="button"
        aria-haspopup="listbox"
        :aria-expanded="open"
        :aria-labelledby="name"
        class="relative w-full bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
        @click.prevent="open = !open"
      >
        <span v-if="value">{{ selected }}</span>
        <span v-else>{{ placeholder }}</span>

        <!-- selectable indicator icon (svg) -->
        ...
      </button>

      <!-- Error message -->
      <small v-if="errors.length > 0" class="text-red-500 mt-3 mx-2">{{
        errors[0]
      }}</small>

      <transition
        leave-active-class="transition ease-in duration-100"
        leave-class="opacity-100"
        leave-to-class="opacity-0"
      >
        <div
          class="absolute mt-1 w-full rounded-md bg-white dark:bg-gray-800 shadow-lg"
          v-show="open"
        >
          <ul
            tabindex="-1"
            role="listbox"
            :aria-labelledby="name"
            aria-activedescendant="listbox-item-3"
            class="max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
          >
            <li
              v-for="item in items"
              :key="item.id"
              :id="`listbox-item-${item.id}`"
              role="option"
              class="text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-gray-700 cursor-default select-none relative py-2 pl-3 pr-9"
              @click="$emit('input', item[preferedValue])"
            >
              <span
                class="ml-3 block font-normal truncate"
                v-text="item.name"
              />

              <!-- Checkmark, only display for selected option. (svg) -->
              ...
            </li>
          </ul>
        </div>
      </transition>
    </div>
  </ValidationProvider>
</template>

<script>
import { ValidationProvider } from 'vee-validate'

export default {
  inheritAttrs: false,
  components: { ValidationProvider },
  props: {
    name: {
      type: String,
      required: true,
    },
    label: {
      type: String,
      required: true,
    },
    hideLabel: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: 'Choose one',
    },
    value: {
      type: [String, Number, Object],
      default: null,
    },
    required: {
      type: Boolean,
      default: true,
    },
    rules: {
      type: String,
      required: false,
    },
    validationMode: {
      type: String,
      default: 'eager',
    },
    items: {
      type: Array,
      required: true,
      default: () => [],
    },
    preferedValue: {
      type: String,
      default: 'id',
    },
  },
  data: () => ({
    open: false,
  }),
  computed: {
    /**
     * The text to be shown based on the selected item and
     * the prefered value as it's key.
     *
     * @returns string
     */
    selected() {
      if (this.value === null || !this.items.length) return ''

      let index = _.findIndex(
        this.items,
        (item) => item[this.preferedValue] === this.value
      )

      return this.items[index].name
    },
    /**
     * The validation rules to be applied in this input field.
     *
     * @returns string
     */
    validationRules() {
      if (!this.required) return this.rules
      return this.rules ? `required|${this.rules}` : 'required'
    },
  },
  mounted() {
    document.addEventListener('click', this.close)
  },
  destroyed() {
    document.removeEventListener('click', this.close)
  },
  methods: {
    toggle() {
      this.open = !this.open
    },
    close(e) {
      if (!this.$el.contains(e.target)) {
        this.open = false
      }
    },
  },
}
</script>

implementation.vue

代码语言:javascript
复制
<template>
  <BaseForm
    ref="form"
    reference="subcategory_form"
    :errors="errors"
    action="/subcategories"
    method="POST"
    @submit="store"
  >
    ...
    <BaseSelect
      class="mb-4"
      name="category_id"
      label="Category"
      placeholder="Choose one"
      :items="categories.data"
      v-model="subcategory.category_id"
    />
  </BaseForm>
</template>

<script>
layout: 'dashboard',
  async fetch() {
    await this.$store.dispatch('categories/load')
  },
  data: () => ({
    subcategory: {
      category_id: null,
      name: '',
    },
    errors: {},
  }),
  computed: {
    categories() {
      return this.$store.state.categories.pagination
    },
  },
  methods: {
    async store() {
      ...
    },
  },
}
</script>

BaseForm.vue

代码语言:javascript
复制
<template>
  <ValidationObserver :ref="reference" tag="div" v-slot="{ handleSubmit }">
    <form
      :action="action"
      :method="method"
      @submit.prevent="handleSubmit(onSubmit)"
    >
      <slot></slot>
    </form>
  </ValidationObserver>
</template>

<script>
import { ValidationObserver } from 'vee-validate'

export default {
  components: { ValidationObserver },
  props: {
    action: {
      type: String,
      required: true,
    },
    method: {
      type: String,
      required: true,
    },
    reference: {
      type: String,
      required: true,
    },
    errors: {
      type: Object,
      default: () => {},
    },
  },

  watch: {
    /**
     * Watch for `errors`.
     *
     * Everytime it changes, assuming it comes from the backend,
     * assign the errors to the `ValidationObserver`.
     */
    errors(val) {
      this.$refs[this.reference].setErrors(val)
    },
  },
  methods: {
    /**
     * Emit `submit` event to the parent component.
     *
     * @returns void
     */
    onSubmit() {
      this.$emit('submit')
    },
  },
}
</script>

那么,这可以用vee来验证吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-10 08:30:48

你可以在ValidationProvider的插槽道具上使用validate函数,这里有一个指南。

https://vee-validate.logaretm.com/v3/advanced/model-less-validation.html#html-file-validation

验证函数接受输入值,该输入值将在内部设置为将被验证的当前值。

代码语言:javascript
复制
<ValidationProvider v-slot="{ validate }">
  <button @click="validate(someValue)"></button>
</ValidationProvider>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66547623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档