将自定义验证应用于 Nuxt 应用程序

让我们将自定义验证应用到示例网站已有的联系页面中。您可能已经注意到现有的联系表单已经使用了 Foundation (Zurb)的验证功能。使用 Foundation 的表单验证是增强 HTML 表单验证的另一种好方法。

如果您想了解更多关于 Foundation 的信息,可以参考其官方指南: https://foundation.zurb.com/sites/docs/abide.html

但如果我们想使用刚刚在 Vue 应用中学到的 VeeValidate 进行自定义验证,那么请按照以下步骤为 Nuxt 安装和设置所需内容:

  1. 通过 npm 安装 VeeValidate

    $ npm i vee-validate
  2. /plugins/ 目录创建插件文件并添加规则:

    // plugins/vee-validate.js
    import { extend } from 'vee-validate'
    import {
      required,
      email
    } from 'vee-validate/dist/rules'
    
    extend('required', {
      ...required,
      message: 'This field is required'
    })
    
    extend('email', {
      ...email,
      message: 'This field must be a valid email'
    })

    这个文件中的所有内容都和我们在 Vue 应用中做的那个文件一样。

  3. Nuxt 配置中添加插件路径:

    // nuxt.config.js
    plugins: [
      '~/plugins/vee-validate'
    ]
  4. build 选项中添加例外:

    // nuxt.config.js
    build: {
      transpile: [
        "vee-validate/dist/rules"
      ],
      extend(config, ctx) {}
    }

    Nuxt 中,默认情况下 /node_modules/ 文件夹会被排除在转译之外,因此在使用 vee-validate 时你会遇到 Unexpected token export 的错误。所以,在运行 Nuxt 应用之前,我们必须添加 /vee-validate/dist/rules.js 以进行转译。

  5. 就像我们在 Vue 应用中做的那样,导入 ValidationObserverValidationProvider 组件:

    // pages/contact.vue
    import {
      ValidationObserver,
      ValidationProvider
    } from 'vee-validate'
    
    export default {
      components: {
        ValidationObserver,
        ValidationProvider
      }
    }
  6. <form> 元素中移除 Foundationdata-abide 属性,但是用 <ValidationObserver> 组件包裹它,并将 submit 事件与 passesprocessForm 方法绑定到 <form> 元素,如下所示:

    <template>
      <ValidationObserver v-slot="{ passes }" ref="observer">
        <form v-on:submit.prevent="passes(processForm)" novalidate>
          <!-- 表单内容 -->
        </form>
      </ValidationObserver>
    </template>

    这一步也和我们在 Vue 应用中做的相同,但是在这个例子中我们添加了 ref="observer",因为我们将在第 8 步中需要它。

  7. 开始使用 <ValidationProvider> 组件重构 <form> 元素内部的所有 <input> 元素,如下所示:

    // pages/contact.vue
    <template>
      <ValidationProvider
        name="name"
        rules="required|min:3"
        v-slot="{ errors, invalid, validated }"
      >
        <label :class="[invalid && validated ? {'is-invalid-label': '{_field_}'} : '']">
          姓名
          <input
            type="text"
            name="name"
            v-model.trim="name"
            :class="[invalid && validated ? {'is-invalid-input': '{_field_}'} : '']"
          >
          <span class="form-error">{{ errors[0] }}</span>
        </label>
      </ValidationProvider>
    </template>

    这一步也和我们在 Vue 应用中做的相同,但是在这个例子中,我们在 v-slot 指令中添加了两个作用域插槽数据属性:invalidvalidated,用于有条件地将类绑定到 <label><input> 元素。因此,如果 invalidvalidated 都为 true,那么我们将分别把 is-invalid-labelis-invalid-input 类绑定到这两个元素上。

    有关 Validation Provider 的作用域插槽数据属性的更多信息,请访问 https://vee-validate.logaretm.com/v2/guide/components/validation-provider.html#scoped-slot-data。

  8. 通过添加以下数据属性来同步 v-model 输入元素,重构 <script> 块中的 data 函数。我们还将在 methods 选项中添加两个方法,如下所示:

    // pages/contact.vue
    export default {
      data() {
        return {
          name: null,
          email: null,
          subject: null,
          message: null
        }
      },
      methods: {
        clear() {
          this.name = null
          this.email = null
          this.subject = null
          this.message = null
        },
        processForm(event) {
          alert('处理中!')
          console.log('提交到服务器...')
          this.clear()
          this.$refs.observer.reset()
        }
      }
    }

    这一步也和我们在 Vue 应用中做的相同,但是在这个例子中,我们在 methods 选项的 processForm 中添加了 clear 方法和 reset 方法。<ValidationObserver> 组件在提交后不会重置表单的状态,所以我们必须手动进行重置,方法是在第 6 步中将 observer 作为引用传递,然后我们可以通过 this.$refsVue 实例访问它。

  9. dirtyinvalidvalidated 这三个作用域插槽数据属性添加到 <ValidationObserver> 组件中,用于切换警告和成功消息的显示,然后让我们按如下方式重构这个组件:

    // pages/contact.vue
    <template>
      <ValidationObserver v-slot="{ passes, dirty, invalid, validated }" ref="observer">
        <div class="alert callout" v-if="invalid && validated">
          <p><i class="fi-alert"></i> There are some errors in your
    form.</p>
        </div>
    
        <div class="success callout" v-if="submitted && !dirty">
          <p><i class="fi-like"></i>&nbsp; &nbsp; Thank you for contacting
    me.</p>
        </div>
      </ValidationObserver>
    </template>
    
    <script>
    export default {
      data() {
        return {
          submitted: false
          //...
        }
      },
      methods: {
        processForm(event) {
          console.log('Posting to the server...')
          this.submitted = true
          //...
        }
      }
    }
    </script>

    在最后一步中,我们添加了一个默认值为 falsesubmitted 数据属性,当表单通过 processForm 方法提交时,该属性将被设置为 true。另一方面,当作用域插槽中的 invalidvalidated 同时为 true 时,警告消息块将显示;而当 submitted 属性为 true 且作用域插槽的 dirty 属性为 false 时,成功消息块将显示。如果任一输入字段是 "dirty" 的(换句话说,当输入字段中存在字符时),dirty 属性将返回 true 布尔值。

您可以看到,我们在 Nuxt 应用中重构的代码与标准 Vue 应用中的做法非常相似。但在 Nuxt 应用中,我们为表单添加了更复杂的逻辑,例如切换警告和成功消息、有条件地将类绑定到 <label><input> 元素,以及在表单提交时重置 <ValidationObserver> 组件。其余输入元素的重构过程与此相同,您可以在本书的 GitHub 仓库 /chapter-7/nuxt-universal/sample-website/ 中找到相关代码。