使用基本数据绑定验证表单

表单是一种用于收集信息的文档。HTML<form> 元素就是一个表单,可以从网页用户那里收集数据或信息。该元素需要包含 <input> 元素来指定我们要收集的数据。但在接收数据之前,我们通常需要验证和过滤这些数据,以确保从用户那里获取真实准确的信息。

Vue 让我们能够轻松地验证来自 v-model 输入元素的数据。让我们从创建一个单文件组件(SFC)的 Vue 应用和 webpack 开始(这些内容您在第 5 章《添加 Vue 组件》的 "使用 webpack 编译单文件组件" 一节中已经学过)。首先,我们将创建一个非常简单的表单,包含提交按钮和显示错误信息的标记,如下所示:

// src/components/basic.vue
<form v-on:submit.prevent="checkForm" action="/" method="post">
  <p v-if="errors.length">
    <b>请更正以下错误:</b>
    <ul>
      <li v-for="error in errors">{{ error }}</li>
    </ul>
  </p>
  <p>
    <input type="submit" value="Submit">
  </p>
</form>

我们稍后会在 <form> 中添加其余的输入元素。现在,让我们先建立基本结构并理解我们需要什么。我们使用 v-on:submit.prevent 来阻止浏览器默认发送表单数据,因为我们将在 Vue 实例的 <script> 块中用 checkForm 方法处理提交:

// src/components/basic.vue
export default {
  data () {
    return {
      errors: [],
      form: {...}
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.errors.length) {
        this.processForm(e)
      }
    },
    processForm (e) {...}
  }
}

JavaScript 部分,我们定义了一个数组来保存验证过程中可能出现的错误。checkForm 逻辑会验证我们稍后将在本节中添加的必填字段。如果必填字段未通过验证,我们会将错误信息推送到 errors 数组中。当表单填写正确且没有发现错误时,数据将被传递给 processForm 逻辑,在那里我们可以对表单数据进行进一步处理,然后再发送到服务器。

验证文本元素

让我们从添加一个单行文本的 <input> 元素开始:

// src/components/basic.vue
<label for="name">Name</label>
<input v-model="form.name" type="text">
export default {
  data () {
    return {
      form: { name: null }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.form.name) {
        this.errors.push('Name required')
      }
    }
  }
}

<script> 块中,我们在 data 函数中定义了一个 name 属性,初始值为 null,该值将通过 <input> 元素的 input 事件更新。当点击提交按钮时,我们会在 if 条件块中验证 name 数据;如果没有提供数据,则将错误信息推送到 errors 数组中。

验证 textarea 元素

接下来我们添加用于多行文本的 <textarea> 元素,其工作方式与 <input> 相同:

// src/components/basic.vue
<label for="message">Message</label>
<textarea v-model="form.message"></textarea>
export default {
  data () {
    return {
      form: { message: null }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.form.message) {
        this.errors.push('Message required')
      }
    }
  }
}

<script> 块中,我们在 data 函数中定义了一个 message 属性,初始值为 null,该值将通过 <textarea> 元素的 input 事件更新。当点击提交按钮时,我们会在 if 条件块中验证 message 数据;如果没有提供数据,则将错误信息推送到 errors 数组中。

验证复选框元素

下一个是单选框 <input> 元素,它将保存默认的布尔值:

// src/components/basic.vue
<label class="label">Subscribe</label>
<input type="checkbox" v-model="form.subscribe">
export default {
  data () {
    return {
      form: { subscribe: false }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.form.subscribe) {
        this.errors.push('Subscription required')
      }
    }
  }
}

我们还将添加以下多个复选框 <input> 元素,它们都绑定到同一个数组 books: []

// src/components/basic.vue
<input type="checkbox" v-model="form.books" value="On the Origin of Species">
<label for="On the Origin of Species">On the Origin of Species</label>

<input type="checkbox" v-model="form.books" value="A Brief History of Time">
<label for="A Brief History of Time">A Brief History of Time</label>

<input type="checkbox" v-model="form.books" value="The Selfish Gene">
<label for="The Selfish Gene">The Selfish Gene</label>
export default {
  data () {
    return {
      form: { books: [] }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (this.form.books.length === 0) {
        this.errors.push('必须选择书籍')
      }
    }
  }
}

<script> 块中,我们在 data 函数中定义了一个 subscribe 属性,初始值为布尔值 false,该值将通过复选框 <input> 元素的 change 事件更新。当点击提交按钮时,我们会在 if 条件块中验证 subscribe 数据;如果没有提供数据或其值为 false,则将错误信息推送到 errors 数组中。

我们对多个复选框 <input> 元素也做了同样的处理,定义了一个 books 属性,初始值为空数组,该值将通过复选框 <input> 元素的 change 事件更新。我们在 if 条件块中验证 books 数据;如果其长度为 0,则将错误信息推送到 errors 数组中。

验证单选框元素

接下来是多个单选按钮 <input> 元素,它们都绑定到同一个属性 gender

// src/components/basic.vue
<label for="male">Male</label>
<input type="radio" v-model="form.gender" value="male">

<label for="female">Female</label>
<input type="radio" v-model="form.gender" value="female">

<label for="other">Other</label>
<input type="radio" v-model="form.gender" value="other">
export default {
  data () {
    return {
      form: { gender: null }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.form.gender) {
        this.errors.push('Gender required')
      }
    }
  }
}

<script> 块中,我们在 data 函数中定义了一个 gender 属性,初始值为 null,该值将通过所选单选按钮 <input> 元素的 change 事件更新。当点击提交按钮时,我们会在 if 条件块中验证 gender 数据;如果没有提供数据,则将错误信息推送到 errors 数组中。

验证 select 元素

下一个是包含多个 <option> 元素的单个 <select> 下拉框:

// src/components/basic.vue
<select v-model="form.favourite">
  <option disabled value="">Please select one</option>
  <option value="On the Origin of Species">On the Origin of Species</option>
  <option value="A Brief History of Time">A Brief History of Time</option>
  <option value="The Selfish Gene">The Selfish Gene</option>
</select>
export default {
  data () {
    return {
      form: { favourite: null }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (!this.form.favourite) {
        this.errors.push('Favourite required')
      }
    }
  }
}

最后一个是多个 <select> 元素,其中包含多个 <option> 元素,它们绑定到同一个数组,即 favourites: []

// src/components/basic.vue
<select v-model="form.favourites" multiple>
  <option value="On the Origin of Species">On the Origin of Species</option>
  <option value="A Brief History of Time">A Brief History of Time</option>
  <option value="The Selfish Gene">The Selfish Gene</option>
</select>
export default {
  data () {
    return {
      form: { favourites: [] }
    }
  },
  methods: {
    checkForm (e) {
      this.errors = []
      if (this.form.favourites.length === 0) {
        this.errors.push('Favourites required')
      }
    }
  }
}

<script> 块中,我们在 data 函数定义了 favourite 属性(初始值为 null),其值将通过 <select> 元素的 change 事件更新。当点击提交按钮时,若未选择任何选项,则推送错误信息到 errors 数组。对于多选 <select> 元素,我们定义了 favourites 数组属性,若其长度为 0 则推送错误信息。

最后我们将在 checkForm 验证通过时调用 processForm 方法。使用 Node.jsqs 包将表单对象序列化为 name=John&message=Hello%20World&subscribe=true&gender=other 格式以便提交:

通过 npm 安装 qs

$ npm i qs

使用示例:

import axios from 'axios'
import qs from 'qs'

processForm (e) {
  var data = qs.stringify(this.form)
  axios.post('../server.php', data)
    .then((response) => {
      // 成功回调
    }, (response) => {
      // 失败回调
    })
}

我们使用 axios 发送数据,并从服务器获取响应(通常是 JSON 格式),然后你可以对响应数据执行某些操作,例如在服务器端显示“成功”或“失败”消息。

更多关于 qs 的信息请访问:https://www.npmjs.com/package/qs axios 文档请访问:https://github.com/axios/axios

完整示例代码可在 GitHub 仓库的 /chapter-7/vue/webpack/ 目录找到。

然而,我们还没有完全完成,因为有时我们可能希望将动态值绑定到表单输入,而不是从 v-model 获取默认值。例如,在我们的示例应用中,对于单个复选框 <input> 元素,我们只为 subscribe 属性获取布尔值,但我们希望使用字符串值 yesno 来代替。我们将在下一节探讨如何更改默认值。