# [Vue cli] 電商網站章節筆記
###### tags: `Vue.js`
### 新增路由路徑及連結

`<router-link>`組件支持用戶在具有路由功能的應用中(點擊)導航。通過to屬性指定目標地址,默認渲染成帶有正確鏈接的<a>標籤,可以通過配置tag屬性生成別的標籤.。另外,當目標路由成功激活時,鏈接元素自動設置一個表示激活的CSS類名。
`<router-link>`比起寫死的`<a href="...">`會好一些,理由如下:
無論是HTML5 history 模式還是hash 模式,它的表現行為一致,所以,當你要切換路由模式,或者在IE9 降級使用hash 模式,無須作任何變動。
在HTML5 history模式下,router-link會守衛點擊事件,讓瀏覽器不再重新加載頁面。
當你在HTML5 history模式下使用base選項之後,所有的to屬性都不需要寫(基路徑)了

### router-view應用解析
https://dotblogs.com.tw/wasichris/2017/03/06/235449
### 製作巢狀路由
https://ithelp.ithome.com.tw/articles/10203823
main.js : 將install的配置檔載入import並開啟

App.vue : 顯示頁面的主內容導入

index.js : import工具及vue分頁,並export分頁內容


## bootstrap套入方式
https://vue-loader.vuejs.org/zh/guide/pre-processors.html#sass
```
<style lang="scss">
/* 在这里撰写 SCSS */
</style>
```
## 反引號使用時機
載入API 及 router.push裡的路徑需使用反引號
```
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/order`;
```
```
vm.$router.push(`/customer_checkout/${response.data.orderId}`)
```
## scoped
在vue文件中的style標籤上,有一個特殊的屬性:scoped。當一個style標籤擁有scoped屬性時,它的CSS樣式就只能作用於當前的組件,也就是說,該樣式只能適用於當前組件元素。通過該屬性,可以使得組件之間的樣式不互相污染。如果一個項目中的所有style標籤全部加上了scoped,相當於實現了樣式的模塊化
## 使用axios串API

* axios語法導入API公式,
* 前方為伺服器路徑,後方signin為指定功能(後端寫入對應功能取得資料)
* this.$http.指定動作post(api取得上方user回傳資料)
* 經由判定式導入並push指定路由路徑
```
this.$http.get(api).then((response) => {
console.log(response.data)
})
```

```
[API]: /signin
[方法]: post
[參數]:
{
"username": "hexscholl@test.com",
"password": "zzxxccvv"
}
[成功回應]:
{
"success": true,
"message": "登入成功",
"uid": "XX4VbV87lRRBXKhZKT7YX6zhsuO2"
}
[失敗回應]:
{
"success": false,
"message": "登入失敗"
}
```
## 暫存至前端記憶體裡
main.js

login頁新增admin

## 將各個vue頁面組合方法
* 在script裡import各元件vue,並套用公式輸出
* 在template裡新增<元件名稱></元件名稱>
* <Sidebar></Sidebar> 也可以等同 <Sidebar/>

## 路由巢狀寫法
* 新增children並將vue子路徑放入陣列中

## 分號逗號運用時機
逗號運算符是可以在表達式中使用的運算符。它用於分離多個不同的表達式,並具有“評估所有以下表達式,然後產生最終表達式的值”的含義。
分號不是運算符,不能在表達式中使用。它用作JavaScript語法的一部分,以標記被視為語句的表達式的結尾。
## 儲存API路徑
在API裡需放入路徑以及申請名稱,當需要更改時會難以管理,因此將API所需的資料放入A資料夾以作即時更改
* 在config資料夾裡的dev.env內建立代數名稱
* 如專案正式執行prod.env也要同步建立

* API代稱放入即可

## 使用API採post行為之流程
目的:將新增產品的項目匯入到後端上,

依據API後端的格式做調整,括號包住data的產品內容



使用bootstrap公式的hide點擊後關閉
回傳產品現有內容,就會顯示新增的商品

## KPI匯入方式
* post 新增到資料庫裡
* get 從資料庫取得資料
* put 修改資料庫裡的資料(玄)
## 刪除鍵執行方式
1. 在頁面上新增刪除的按鈕

2. 採用jquery事件觸發開啟,新增openDelModal來使用參數item來讓程式辨別哪一筆資料,並觸發"API觸發事件"

3. 串連API刪除事件(API本身已寫好刪除功能,無需再寫一次)

## 表格匯入API資料
使用

* username 是API資料裡提供
* Chris是新增變數在指出圖片放置位置

* 在這裡命名url取代api為串接的元素,放入指定process.env.APIPATH路徑
* https://developer.mozilla.org/en-US/docs/Web/API/FormData/append
* 採用方法post方法將值帶入,注意這邊要帶入的東西較多
* 最後使用set強制匯入載入資料
## 取得瀏覽圖示的兩個方法
1. Vue Loading Overlay Component
https://www.npmjs.com/package/vue-loading-overlay
* 下載npm後在main.js放入套件並啟用在全域,至Vue頁面上放置在templete下方,並新增布林值變數,並在載入API動作前開啟,在完成載入後關閉,如此一來當畫面在瀏覽狀態時就會出現loading的圖示
2. fontawesome icon
https://fontawesome.com/icons/spinner?style=solid
* 獨特的設定位置:將gdn放入index.html的Title下方即可使用
* data新增變數(代布林值)後,放入指定位置設定開啟與結束時機
補充:如果要點擊到特定產品後產生圖示,便可帶入參數id,使用判定式當產品ID相同時就會顯示
```
<button type="button" class="btn btn-outline-secondary btn-sm"
@click ="getProduct(item.id)">
<i class="fas fa-spinner fa-spin" v-if="status.loadingItem === item.id"></i>
查看更多
</button>
```
* 將變數loadingItem指向產品id,記得結束時要使其變空物件。
```
getProduct(id){ //click開啟model的動作,並取得既存資料
const vm = this;
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/product/${id}`;
vm.status.loadingItem =id;
this.$http.get(api).then((response) => {
//console.log(response);
vm.product = response.data.product; //將取得資料的products項目匯入data的空陣列裡
$('#productModal').modal('show');
vm.status.loadingItem ='';
});
},
```
## Alert錯誤提示
https://github.com/a-howw/HexSchool_Vue.js/issues/12
## 多個Vue及js功能載入過程
第一種情況,將Vue分成多元件再組合成一個主頁面上
第二種情況,將js功能載入主頁面上的DOM元素做使用
### 彙整Vue子元件
1. 新增子Vue元件
2. 在主頁面使用import匯入路徑,並export連結物件
```
import Pagination from '@/components/Pagination';
export default {
components:{
Pagination,
},
```
## Filter載入js功能
將所需的功能個別分配多個js中,頁面需要用上時便可直接在匯入使用
1. 新增js元件
1. 在main.js檔案裡使用import匯入路徑,並使用對應method開啟
1. 再將宣告子令currency放入主頁面上的DOM元素上
```
import currencyFilter from './filters/currency';
Vue.filter('currency',currencyFilter); //全域啟用瀏覽中的樣式
```
匯入方式如下以|直線加上命名變數currency,數字便會自帶百位小數點
```
<td class="text-right">
{{item.total| currency}}
</td>
```
## 依照API需求回傳參數
```
[API]: /api/:api_path/cart
[方法]: post
[參數]: { "data": { "product_id":"-L9tH8jxVb2Ka_DYPwng","qty":1 } }
[成功回傳]:
{
"success": true,
"message": "已加入購物車",
"data": {
"product_id": "-L9tH8jxVb2Ka_DYPwng",
"qty": 1,
"coupon_code": "",
"id": "-LAl5v_2MhWeh3linQxx",
"total": 600,
"final_total": 600,
"product": {
"category": "衣服3",
"content": "這是內容",
"description": "Sit down please 名設計師設計",
"id": "-L9tH8jxVb2Ka_DYPwng",
"imageUrl": "test.testtest",
"is_enabled": 1,
"num": 1,
"origin_price": 500,
"price": 600,
"title": "[賣]動物園造型衣服3",
"unit": "個"
}
}
}
```
* 因KPI記載需取得兩種以上的資料,因此使用物件{}的方式載入相關參數
* 再依照指示將資料匯入post(api,{data:cart})

## 提示欄位不完整 vee-validate
參考資料:https://hao1229.github.io/2019/08/09/EcommercePractice8/
#### 將英文提示字幕,轉換為中文語系
1. 安裝 vue-i18n
在 terminal 中輸入 'npm install vue-i18n --save'
2. 在 main.js 中將 vue-i18n import 進來
import VueI18n from 'vue-i18n';Vue.use(VueI18n);
3. 將 VeeValidate.Validator.localize('zh_TW', zhTWValidate) 及 Vue.use(VeeValidate) 刪除,並加入下列程式碼
```
const i18n = new VueI18n({
locale: 'zhTW'
});
Vue.use(VeeValidate, {
i18n,
dictionary: {
zhTW
}
});
```
4. 在 Vue 物件中新增 i18n
```
new Vue({
i18n,
el: '#app',
components: { App },
template: '<App/>',
router,
})
```
#### 執行提示姓名欄位未輸入
* 載入v-validate="'required'"
* 顯示地點放入v-if="errors.has('name')"當欄位未填空系統為true

#### 執行提示信箱欄位未輸入
* 信箱欄位可使用{{ errors.first('email') }}系統協助判定email格式是否正確

#### 執行所有欄位未輸入的項目
* 驗證所有欄位都完成才能匯入API公式
* 原先chrome內建自動判定提示(input加上required的前提)
* 導入post函式裡的先匯入下列公式,再採用判斷式if=true才發送API

```
this.$validator.validate().then((valid) => {
if (valid) {
this.$http.post(api , {data:order}).then((response) => {
console.log("訂單已建立" , response);
if (response.data.success) {
vm.$router.push(`/customer_checkout/${response.data.orderId}`); //傳至路徑,取得後端資料庫裡的orderId
}
vm.isLoading = false;
});
} else {
console.log('欄位不完整');
}
});
```
## 導航守衛
請參考[官方資料](https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB)
* 新增判定公式至main.js頁面,並載入API驗證使用者是否已登入過,如果已完成登入,系統便會放行至指定頁面,如果還未便會重新導入登入頁面。
```
router.beforeEach((to, from, next) => {
console.log('to', to, 'from', from, 'next', next);
// ...
if (to.meta.requiresAuth) {
const api = `${process.env.APIPATH}/api/user/check`;
axios.post(api).then((response) => {
console.log(response.data);
if (response.data.success) {
next();
} else {
next({
path: '/login',
});
}
});
} else {
next();
}
});
```
* 到router頁面新增`meta:{requiresAuth:true}`需驗證的指定vue元件
* 當使用者輸入錯誤網址時,使用redirect語法轉為登入頁面
```
export default new Router({
routes: [
{
path: '*',
redirect: 'login',
},
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
meta: { requiresAuth: true },
},
```
## 套用bootstrap版型(載入模板css / html)
在Boostrap範例所取得的css以及html的原始碼套入vue cli裡做使用
CSS
第一步:建立一個dashboard.scss將css放入
第二步:將上方scss載入all.scss作統一管理import
第三步:all.scss會串連至預設的app.vue裡啟動
補充:如vue元件不想被全域scss所應用,需在style標籤增加scoped,便可獨立應用
template
第一步:新增dashboard主頁面,再分離sidebar以及navbar兩個元件
第二步:兩元件載入主頁面,需要做1. import呼叫,2.啟用,3.掛在template
## 使用openModel開啟彈跳視窗
在Methods內寫入函式
> 需將import $ from 'jquery';匯入scrpit裡來啟動jquery變數元件$
```
openModal(){
$('#productModal').modal('show');
}
```
亦可帶入參數或加入判斷式等條件來開啟指定Model
```
openModal(isNew , item){
if(isNew){
this.tempProduct= {};
this.isNew=true;
}else{
this.tempProduct= Object.assign({},item); //es6語法,為了避免item與左方物件相同
this.isNew=false;
}
$('#productModal').modal('show');
},
```
## 製作分頁鍵
後端將每項產品都標記好頁數、目前頁數等等資訊,我們只要透過getProduct取得API資訊後,代入頁數page將分頁的資訊回傳到變數中,就可以操控並設計分頁元件
* 回傳給變數pagination
```
getProducts(page = 1){ //ES6預設值,如無代數值便會使用原先1,有參數則使用參數數值
const api = `${process.env.APIPATH}/api/${process.env.CUSTOMPATH}/admin/products?page=${page}`;
const vm = this;
vm.isLoading = true;
this.$http.get(api).then((response) => {
console.log(response.data);
vm.isLoading= false;
vm.products = response.data.products //將取得資料的products項目匯入data的空陣列裡
vm.pagination = response.data.pagination;
});
},
```
template的部分分為三大項目
* 上頁元件
* 目前頁面
* 下頁元件
```
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item" :class="{'disabled': !pagination.has_pre }">
<a class="page-link" href="#" aria-label="Previous"
@click.prevent="getProducts(pagination.current_page - 1)">
<span aria-hidden="true">«</span>
<span class="sr-only">Previous</span>
</a>
</li>
<li class="page-item" v-for="page in pagination.total_pages" :key="page"
:class="{'active': pagination.current_page === page}">
<a class="page-link" href="#" @click.prevent="getProducts(page)">{{ page }}</a>
</li>
<li class="page-item" :class="{'disabled': !pagination.has_next }">
<a class="page-link" href="#" aria-label="Next"
@click.prevent="getProducts(pagination.current_page + 1)">
<span aria-hidden="true">»</span>
<span class="sr-only">Next</span>
</a>
</li>
</ul>
</nav>
```
> 為了增加使用的便利性,建議將頁籤寫成元件,在合適的頁面上直接套用即可
## 問號區
當產品圖片要借用for迴圈產生的item.url時,就可以使用動態:style並匯入下方公式
```
<div style="height: 400px; background-size: cover; background-position: center"
:style="{backgroundImage:`url(${item.imageUrl})`}" >
<!-- 插入連結的方式,上方為ES6反引號插入大括號的用法 -->
```
## 網址帶入產品ID
在router裡新增路徑,注意要將後方代的產品編號對應後端的id項目
```
{ path:'customer_checkout/:orderId',
name:'CustomerCheckout',
component: CustomerCheckout,
},
```
在vue購物元件裡執行post的購物頁面,當傳送成功後便將ID傳入上方路徑中
```
if (response.data.success) {
vm.$router.push(`/customer_checkout/${response.data.orderId}`); //傳至路徑,取得後端資料庫裡的orderId
}
```
開啟新增的Vue頁面,在底部新增params路由公式,將WWW上的ID匯入空陣列上使用,經上面步驟後,便可以使用get取得這筆ID的訂單明細,變相告知後端資料庫要取得哪一筆資料,相似於代參數。
```
created(){
this.orderId = this.$route.params.orderId; //匯入參數公式之一, oderId必須要對應router裡的path路徑名稱
console.log(this.orderId);
this.getOrder();
}
```
在取得資料時將ID傳入,以便資料庫知道調出特定資料至頁面上
```
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) => {
console.log(response);
if(response.data.success){
vm.getOrder() //一旦點擊,後端系統便會將is_paid轉為true
}
vm.isLoading = false;
});
},
```
總結就是利用WWW網址上的數值,將資料傳送到另一個vue元件上使用。
## VeeValidate 表單欄位的守護者
功能如下
* 表單輸入空白會顯示自定義的提醒說明
* email有專屬的程式碼,會針對輸入細節提醒
* email的字定義的提醒文字,需載入中文版
* 送出表單如有required程式碼,chrome瀏覽器會偵測欄位錯誤
* 如要使用內建的submit驗證,官網裡有相關的程式碼可以載入,並將其放入api傳送的函式裡做判定
官方資料:http://vee-validate.logaretm.com/v2/guide/events.html#changing-default-events
影片解說:https://www.udemy.com/course/vue-hexschool/learn/lecture/10896798#notes