Vue 雖然也能搭配 HTML 5 的 Form Validation,但 Vue 的 Model-based 與 HTML 的 Element-based 則大異其趣,Model-based 更直覺且可讀性更高。
Version
Vue 2.6.11
Vuelidate 0.7.5
HTML 5
當沒有任何輸入時,按下 Submit
會出現警告訊息。
當輸入字串長度小於 5 時,按下 Submit
也會出現警告訊息。
當有輸入字串且長度大於 5 時,才會觸發原本的 submit
event。
<template>
<form @submit.prevent="onSubmit">
<input ref="username" @invalid.capture.prevent="onInvalid" required minlength="5">
<button>Submit</button>
<p>{{ msg }}</p>
</form>
</template>
<script>
let onSubmit = function() {
this.msg = 'Submit event fired'
}
let onInvalid = function() {
if (this.$refs.username.validity.valueMissing)
this.msg = 'User name is required'
else if (this.$refs.username.validity.tooShort)
this.msg = 'User name is too short'
}
export default {
name: "App",
data: () => ({
msg: ''
}),
methods: {
onSubmit,
onInvalid
}
}
</script>
第 2 行
<form @submit.prevent="onSubmit">
<input ref="username" @invalid.capture.prevent="onInvalid" required minlength="5">
<button>Submit</button>
<p>{{ msg }}</p>
</form>
若要使用 HTML 5 Form Validation,則 <input>
必須放在 <form>
內,且不能使用 <button>
的 click
event,而要使用 <form>
的 submit
event。
<form @submit.prevent="onSubmit">
<form>
的 submit
event 預設會 post 到 server,因為現在會使用 Ajax 打 RESTful API,因此會在 @submit
加上 prevent
modifier 避免 <form>
post 到 server,相當於 event.preventDefault()
。
<input ref="username" @invalid.capture.prevent="onInvalid" required minlength="5">
由於我們想判斷 <input>
為 必填
且 長度需大於 5
,使用了 HTML 5 的 required
與 minlength="5"
attribute。
HTML 5 判斷時會觸發 invalid
event,且會在 <input>
以 popup 顯示預設錯誤訊息,但因為我們只想借用 HTML 5 Form Validation,並不想以 popup 顯示,因此使用了 invalid.capture.prevent
。
- capture:原本的 HTML 5 會先由內而外觸發
popup
event 然後才是invalid
event,為了阻擋 popup 顯示,特別使用capture
modifier 改成由外向內先觸發invalid
event,如此才能避免 popup 顯示。 - prevent:為了避免
invalid
event 執行完又觸發popup
event,因此使用prevent
modifier 避免invalid
event 執行完後繼續執行popup
event。
HTML 5 主要以 element 控制,而非 Vue 的 model-based 寫法,因此特別加上
ref="username"
,稍後將以username
控制<input>
element。
14 行
let onInvalid = function() {
if (this.$refs.username.validity.valueMissing)
this.msg = 'User name is required'
else if (this.$refs.username.validity.tooShort)
this.msg = 'User name is too short'
}
HTML 5 允許我們由 element 的 validity.valueMissing
與 validity.tooShort
判斷 required
與 minlength="5"
是否成立。
由於 validity
是在 <input>
element 下,因此必須透過 this.$refs.username
取得 <input>
。
第 10 行
let onSubmit = function() {
this.msg = 'Submit event fired'
}
當 invalid
event 都沒錯時,才會執行 submit
event 完成 Form Validation。
可發現 HTML 5 Form Validation 寫法非常繁瑣,除了須小心控制 event 外,還必須小心處理 element,更可發現 Vue 的 model-based 寫法之精簡
Add Vuelidate
$ yarn add vuelidate
使用 Yarn 安裝 vuelidate
。
Main
main.js
import Vue from 'vue'
import App from './App.vue'
import Vuelidate from "vuelidate"
Vue.use(Vuelidate)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
第 3 行
import Vuelidate from "vuelidate"
引用 vuelidate
。
第 5 行
Vue.use(Vuelidate)
Vue 使用 Vuelidate。
Component
App.vue
<template>
<div>
<input v-model="username">
<button @click="onClick">Submit</button>
<p>{{ msg }}</p>
</div>
</template>
<script>
import { required, minLength } from 'vuelidate/lib/validators'
let onClick = function() {
if (!this.$v.username.required)
this.msg = 'User name is required'
else if (!this.$v.username.minLength)
this.msg = 'User name is too short'
else
this.msg = 'Submit event fired'
}
export default {
name: 'App',
data: () => ({
username: '',
msg: ''
}),
validations: {
username: {
required,
minLength: minLength(5)
}
},
methods: {
onClick
}
}
</script>
第 3 行
<input v-model="username">
<button @click="onClick">Submit</button>
<p>{{ msg }}</p>
<input>
使用 v-model
綁定到 username
model,<button>
則將 click
event 綁定到 onClick()
。
我們可發現在 Vue 使用相當直覺,不必將
<input>
包在<form>
裡,也不必改用<form>
的submit
event 與prevent
modifier,更不必在invalid
event 使用較罕用的capture
modifier,就如同一般 HTML 用法
23 行
data: () => ({
username: '',
msg: ''
}),
由於 Vue 為 model-based 寫法,因此要宣告 <input>
所綁定的 username
model。
這也與 HTML 的 element-based 寫法不一樣,不必如 HTML 要搭配
ref
attribute 設定 element 名稱。
27 行
validations: {
username: {
required,
minLength: minLength(5)
}
},
新增 validations
property,在其內宣告與 model 相同名稱的 username
property,並將要驗證的 required
與 minLength
組合成 object。
這也與 HTML 以 attribute 設定驗證功能不一樣,而是入境隨俗以 model-based 方式,改為對 model 驗證,而不是對 element 驗證
第 10 行
import { required, minLength } from 'vuelidate/lib/validators'
但 required
與 minLength
則以 function 提供,因此要從 vuelidate/lib/validators
引用。
HTML 的驗證功能是 attribute;Vuelidate 則是 function
12 行
let onClick = function() {
if (!this.$v.username.required)
this.msg = 'User name is required'
else if (!this.$v.username.minLength)
this.msg = 'User name is too short'
else
this.msg = 'Submit event fired'
}
以 this.$v
下的 model 的 required
與 minLength
property 判斷,true
則通過驗證,false
則失敗,非常直覺。
HTML 必須透過 element 下的
validity
判斷,因此要使用ref
設定 element 名稱,且valueMissing
與tooShort
又與required
與minLength
不一樣;Vuelidate 則在this.$v
使用 model,且一樣是required
與minLength
,非常直覺
Conclusion
- 可發現 HTML 5 的 element-based 寫法非常 tricky 也不直覺,但 Vuelidate 則充分利用 Vue 的 model-based 特性,一切都很直覺,可讀性又高
Reference
Learn Vue, Getting Smart with Vue Form Validation - Vuelidate Tutorial