0%

vue出一個電商網站-表單驗證補充

表單驗證補充

在課程中原本是用第二版的vee-validate,
那在第二版是透過vue的指令和html的屬性來驗證。
課堂上有提供安裝與指令步驟
那新版的vee-validate有很大的不同,就是新版是用元件的方式來進行驗證。
step1.
先輸入指令npm uninstall vee-validate,將vee-validate給卸載。
step2.
接著輸入npm install vee-validate --save,來安裝新版的vee-validate套件。
step3.
接著,你運行vue的環境,此時,會跳出一些錯誤,我們先不管它。
step4.
接下來,到main.js檔案中做一些調整。
我們先將原本引入vee-validate的內容給刪掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
---main.js---
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import Loading from 'vue-loading-overlay'; // 引入overlay元件
import 'vue-loading-overlay/dist/vue-loading.css'; // 引入overlay元件
import 'bootstrap'
import App from './App'
import router from './router'
import './bus'
import currencyFilter from './filters/currency'
//import VeeValidate from 'vee-validate'; // 原本的vee-validate內容拿掉
//import zhTWValidate from 'vee-validate/dist/locale/zh_TW' // 原本的vee-validate內容拿掉
import zhTW from 'vee-validate/dist/locale/zh_TW'
import VueI18n from 'vue-i18n'

Vue.use(VueAxios, axios)
//Vue.use(VeeValidate); // 原本的vee-validate內容拿掉
//VeeValidate.Validator.localize('zh_TW', zhTWValidate); // 原本的vee-validate內容拿掉
Vue.config.productionTip = false
Vue.component('Loading', Loading); // 啟用overlay元件
Vue.filter('currency', currencyFilter); // 啟用fiter元件


// Vue.use(VeeValidate, {
// events: 'input|blur', //這是為了讓使用者離開該欄位時觸發驗證
// i18n,
// dictionary: {
// zhTW
// }
// })

你可以看到,我們把引入檔案和創建vee-validate元件的內容給註解掉了。
它們是屬於舊版的驗證。

step5.
那因為新版是使用元件的方式來驗證,所以,我們要將這些元件給導入進來。
接著,我們在main.js中引入以下的程式碼,還有元件的規則都貼進來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---main.js---
<!--引入元件-->
import { ValidationObserver, ValidationProvider, extend, localize, configure } from 'vee-validate';
import TW from 'vee-validate/dist/locale/zh_TW.json'
import * as rules from 'vee-validate/dist/rules';
<!--引入元件-->

<!--元件規則-->
Object.keys(rules).forEach((rule) => {
extend(rule, rules[rule]);
});

localize('zh_TW', TW);

Vue.component('ValidationObserver', ValidationObserver)
Vue.component('ValidationProvider', ValidationProvider)

configure({
classes: {
valid: 'is-valid',
invalid: 'is-invalid'
}
});
<!--元件規則-->

那小小解釋一下,引入的內容分別代表什麼意思
引入元件部分
第一行中,ValidationObserver是代表驗證的元件,ValidationProvider是input驗證元件。
extend是代表擴充功能,localize代表語系的設定。
第二行,是直接將繁體中文引入的檔案。
第三行,是比較大的不同。在新版的vee-validate中都是用規則化的驗證。

元件規則部分
在Object.keys的內容,是代表說我們先把rules規則先導出來,並加到extend的擴充功能裡面。
如此一來,才能運用這些規則。

localize('zh_TW', TW)的部分,就套件繁體中文功能的部分。
Vue.component('ValidationObserver', ValidationObserver)的部分,就代表input單一欄位驗證功能的部分。
Vue.component('ValidationProvider', ValidationProvider)的部分,是代表整體form表單的驗證功能部分。

在configure中,就是className的設定檔。

step6.
接著,回到訂購表單頁面中。
我們將email欄位的驗證部分改為新版的vee-validate的內容

1
2
3
4
5
6
7
8
9
10
11
<validation-provider rules="required|email" v-slot="{ errors, classes }">
<!-- 輸入框 -->
<div class="form-group">
<label for="email">Email</label>
<input id="email" type="email" name="email"
class="form-control" v-model="form.user.email" :class="classes">
<!-- 錯誤訊息 -->
<span class="invalid-feedback">{{ errors[0] }}</span>
</div>

</validation-provider>

a.你可以看到我們先用validation-provider元件將那些要驗證的內容給包起來。
b. 在input的欄位中,記得要加入v-model的綁定效果喔。
接下來,介紹一下裡面的功能
c.在validation-provider標籤中,rules是代表它是吃什麼規則的,rules="required|email",代表該input欄位是必填的,
然後,後面是跟著它是吃什麼規則的方法,這邊是吃email,而email是vee-validate本身就有提供的規則,所以,不用自己自訂義。
d. v-slot="{errors}",是可以把外部的錯誤資訊導入到validation-provider標籤內,供裡面的元件使用,
你可以看到在<span>{{ errors[0] }}</span> 裡面用的errors就是從取外部娶進來的資料。

加上以上的內容後,email欄位的驗證效果就可以正常運作囉~~~

step7.
接著,我們要為剛剛修改的email驗證方式增加className,我們可以透過v-slot來增加。

1
2
3
4
5
6
7
8
9
10
11
<validation-provider rules="required|email" v-slot="{ errors, classes }">
<!-- 輸入框 -->
<div class="form-group">
<label for="email">Email</label>
<input id="email" type="email" name="email"
class="form-control" v-model="form.user.email" :class="classes">
<!-- 錯誤訊息 -->
<span class="invalid-feedback">{{ errors[0] }}</span>
</div>

</validation-provider>

你可以看到我們在v-slot中加入了classes並在input欄位中透過v-bind來動態的綁定這個classes,
那這個classes的內容,就是我們在main.js檔中定義的configure裡面的內容喔。
另外,我們也為最後的span套上了bootstrap的invalid-feedback的樣式,來讓它的內容呈現紅色的字樣。

step8.
為整體的表單做驗證。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<validation-observer  class="col-md-6" v-slot="{ invalid }">
<form>
<validation-provider rules="required|email" v-slot="{ errors, classes }">
<!-- 輸入框 -->
<div class="form-group">
<label for="email">Email</label>
<input id="email" type="email" name="email"
class="form-control" v-model="form.user.email" :class="classes">
<!-- 錯誤訊息 -->
<span class="invalid-feedback">{{ errors[0] }}</span>
</div>

</validation-provider>
<div class="text-right">
<button class="btn btn-danger" type="submit" @click.prevent="createOrder" :disabled="invalid">送出訂單</button>
</div>
</form>

</validation-observer>

你可以看到,我們直接用validation-observer標籤把form表單給包起來,並且在validation-observer的標籤上有一個v-slot可以將invalid的
值往內傳。
所以,我們透過invalid來跟送出訂單的按鈕的disabled屬性作綁定,如果表單內的格式有誤,這個按鈕式沒有辦法被按下去的。

按照以上的方式,我們就可以順利的使用新版的vee-validate的驗證功能囉~~

step9.
另外,有關送出表單到後端api的內容也要修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<validation-observer class="col-md-6" v-slot="{ invalid, handleSubmit }">
<form @submit.prevent="handleSubmit(submitForm)">
<validation-provider rules="required" v-slot="{ errors, classes }">
<!-- 輸入框 -->
<div class="form-group">
<label for="useraddress">收件人地址</label>
<input id="useraddress" type="text" name="地址"
class="form-control" v-model="form.user.address" :class="classes" placeholder="請輸入地址" >
<!-- 錯誤訊息 -->
<span class="invalid-feedback">{{ errors[0] }}</span>
</div>
</validation-provider>

<validation-provider v-slot="{ errors, classes }">
<!-- 輸入框 -->
<div class="form-group">
<label for="comment">留言</label>
<textarea name="" id="comment" class="form-control" cols="30" rows="10" v-model="form.message"></textarea>
</div>
</validation-provider>


<div class="text-right">
<button class="btn btn-danger" :disabled="invalid">送出訂單</button>
</div>


</form>

</validation-observer>
</template>

<script>
methods:{
submitForm() {
const vm = this;
const order = vm.form;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/order`;
vm.isLoading = true;
this.$http.post(api,{data:order}).then((response) => {
console.log('訂單已建立', response);
})
console.log('送出表單');
vm.isLoading = false;
}
}
</script>

你可以看到在validation-observer標籤上是綁定了handleSubmit事件。
在內層的form標籤上@submit.prevent="handleSubmit(submitForm)"綁定了這個submitForm事件。
那接著,你再到js中寫入submitForm事件,去傳入新增的表單內容到後端中,如此,就是一個完整的表單功能囉。

結帳頁面製作

step1.
首先,先新增一個付款完成後,跳頁的頁面。
我們直接在pages的資料夾中,新增一個CustomerCheckOut.vue的元件檔。
那在課堂上有提供取得訂單列表的api
所以,我們到index.js檔案中,新增這個元件的名稱和路徑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---index.js--
import CustomerCheckOut from '@/components/pages/CustomerCheckOut' // 引入customer_CheckOut元件

{
path: '/',
name: 'DashBoard',
component: DashBoard,
children:[
{
path:'customer_order',
name: 'CustomerOrder',
component: CustomerOrder,
},
{
path:'customer_CheckOut/:orderId', // 新增這個customer_CheckOut的元件和路徑
name: 'CustomerCheckOut',
component: CustomerCheckOut,
},
]
},

以上,我們就引入了customer_CheckOut這個元件的名稱和路徑。
那你要注意一下,取得某一筆訂單的路徑後面要接上這個訂單的id喔。

step2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
methods:{
submitForm() {
const vm = this;
const order = vm.form;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/order`;
vm.isLoading = true;
this.$http.post(api,{data:order}).then((response) => {
console.log('response', response);
console.log('response1', response.data.success);
if(response.data.success){
console.log('訂單已建立');
vm.$router.push(`/customer_CheckOut/${response.data.orderId}`); // 跳轉頁面
}
})
vm.isLoading = false;
}
}

在我們成功送出訂單之後,會直接用push的方式來跳轉到取得訂單頁面。

step3.
接下來,撰寫customer_CheckOut的頁面囉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---customer_CheckOut.vue---
<script>
export default{
data(){
return{
orderId:'',
}
},
created(){
this.orderId = this.$route.params.orderId; // 取得該router的id
console.log(this.orderId);
}
}
</script>

這邊你要特別注意,在this.$route.params.orderId的orderId的變數名稱。

1
2
3
4
5
6
---index.js---
{
path:'customer_CheckOut/:orderId', //都要叫orderId
name: 'CustomerCheckOut',
component: CustomerCheckOut,
},

這邊你要特別注意,在this.$route.params.orderId的orderId的變數名稱要跟你在index.js檔案裡面orderId變數名稱一樣,
不然,編譯器會找不到orderId

step4.
接著,將公版的訂單列表格式貼近來之後,將後端的訂單內容取進來,並放進去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script>
export default{
data(){
return{
orderId:'',
order:{
user:{
email:''
}
}
}
},
methods:{
getList(){
const vm = this;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/order/${vm.orderId}`;

this.$http.get(api).then((response) => {
vm.order = response.data.order;
})
}
},
created(){
this.orderId = this.$route.params.orderId;
console.log(this.orderId);
this.getList();
}
}

</script>

以上的內容你就可以看到我們將後端的data.order裡面的資料取進來放在order物件中,
並再將這個order物件裡面的內容呈現在訂單列表裡面囉,

step5.
訂單列表中的確定付款去的按鈕。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<form class="col-md-6" @submit.prevent="payOrder">
<table class="table">
<thead>
<th>品名</th>
<th>數量</th>
<th>單價</th>
</thead>


</table>
<div class="text-right" v-if="order.is_paid === false">
<button class="btn btn-danger">確認付款去</button>
</div>
</form>

<script>
methods:{
payOrder(){
const vm = this;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/pay/${vm.orderId}`;
vm.isLoading = true;
this.$http.post(api).then((response) => {
vm.getList();
vm.isLoading = false;
})
}
}
</script>

你可以看到我們為提交表單新增了一個payOrder的方法,並在提交完成後重新讀取一次該表單的內容,
此時,在付款狀態欄位的內容就可以被刷新囉。

以上就完成付款的功能囉。

最終作業說明

目前我們專案都是用npm run dev的方式來運行專案,但是,我們不可能直接將這種形式的檔案給別人看。
所以,我們一定要編譯完成後,上傳到正式的伺服器上給別人。
那在dev.env.js檔案中的內容,記得也要加到正式版的prod.env.js中喔。
等到你加完之後,就可以輸入npm run build
接著,你就要用live server的方式來開啟dist資料夾中的index.html檔案囉。

小插曲- npm run build沒有辦法呈現頁面

當我用live server打開dist資料夾中的index.html後,沒有畫面,
打開console.log後,看到MIME的相關錯誤的訊息。
那我就將在config資料夾中的index.js檔案中的build屬性中的assetsPublicPath從’/‘改成’./‘,
就可以成功讀取到相關的檔案,也就不會再出現無法呈現頁面的狀態囉。

分享另一個小地方,
如果我們釋出的檔案不是在跟目錄底下,
比如不是在 http://landy510.github.io 底下,而是在http://landy510.github.io/Vue-testing底下,
那這樣我們需要做一些調整,
此時,我們要去config資料夾底下的index.js中的
build屬性中的assetsPublicPath的屬性值從’./‘ 改成’/Vue-testing/‘ 如此就能在Vue-testing底下做運行囉。