文章目錄
- 1. 專案基礎架構
- 1.1 專案基礎架構
- 1.2 主要插件
- 1.3 路由封裝
- 1.4 sessionstorage的封裝
- 1.5 介面錯誤攔截
- 1.6 介面環境的設定
- 1.7 MOCK設定
- 2.首頁功能開發
- 3.登錄功能開發
- 4.產品站功能開發
- 5.商品詳情頁面
- 6.購物車頁面
- 7.ElementUI集成
- 8.訂單確認功能
- 9.訂單支付功能
- 10.訂單串列功能實作
- 11.原始碼地址
1. 專案基礎架構
專案使用到的技術堆疊:Vue全家桶,后臺介面線上調聯,Sass預編譯,ElementUI,前端優化,微信支付寶支付…
1.1 專案基礎架構
專案的基本結構:
VueProject
└─ mistore
├─ babel.config.js
├─ package-lock.json
├─ package.json
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ README.md
└─ src
├─ api
│ └─ index.js
├─ App.vue
├─ assets
│ └─ logo.png
├─ components
│ ├─ NavFooter.vue
│ └─ NavHeader.vue
├─ main.js
├─ pages
│ ├─ alipay.vue
│ ├─ cart.vue
│ ├─ detail.vue
│ ├─ home.vue
│ ├─ index.vue
│ ├─ login.vue
│ ├─ order.vue
│ ├─ orderConfrim.vue
│ ├─ orderList.vue
│ ├─ orderPay.vue
│ └─ product.vue
├─ router.js
├─ storage
│ └─ index.js
├─ store
└─ util
└─ index.js
首先貼出我們專案的幾個大體實作效果圖

1.2 主要插件
“axios”: “^0.21.1”
“element-ui”: “^2.15.1”,
“node-sass”: “^5.0.0”,
“sass-loader”: “^11.0.1”,
“vue-awesome-swiper”: “^4.1.1”,
“vue-cookie”: “^1.1.4”,
“vue-lazyload”: “^1.3.3”,
…
1.3 路由封裝
使用路由懶加載的方式進行路由的設定,根據我們的專案設計稿封裝路由
偽代碼如下:
import vue from 'vue';
import Router from "vue-router"
vue.use(Router);
// 使用路由懶加載的方式加載路由
var cart = () => import('./pages/cart.vue');
...
var router=new Router({
routes: [
// 初始默認路由(home)
{
children: [
// 商品詳情(動態)
// 大圖展示(動態)
// 首頁
]
},
// 購物車路由
// order父路由
children: [
// 訂單串列
// 訂單確認
// 訂單支付
]
},
//登錄
],
mode:'history'
});
export default router
1.4 sessionstorage的封裝
為什么要封裝storage:
- Storage本身雖然有Api,但是只是簡單的鍵值對的形式
- Storage只能存盤字串,需要人工轉換成json物件
- Storage只能一次性清空,不能單個清空
我們通常在Storage中存盤json物件,因此我們需要自己封裝Storage方法,
/*
Storage封裝
*/
const STORAGE_KEY = 'mall';
export default {
// 存盤值
setItem(key, value, modules_name) {
if (modules_name) {
var all = this.getItem(modules_name)
all[key] = value;
// 這里遞回本方法將modules_name作為key(已有),再將當前添加進去的all放進此module_name中,此時的val就包含了所有值,最后直接添加即可
this.setItem(modules_name, all)
} else {
//只傳入兩個引數:
let val = this.getStorage();
console.log(val);
val[key] = value;
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(val));
}
},
/*
獲取值(可以傳入一個值也可傳入兩個值)
一個引數:沒有moudle直接單物件
一個引數:獲得moudle下的key對應的物件
*/
getItem(key, modules_name) {
if (modules_name) {
let val = this.getItem(modules_name);
if (val) return val[key]
}
return this.getStorage()[key];
},
// 獲取整個資料(轉為json格式):將資料轉換為json格式,
getStorage() {
return JSON.parse(window.sessionStorage.getItem(STORAGE_KEY) || '{}')
},
// 洗掉某一個值
clear(key, modules_name) {
let val = this.getStorage();
if (modules_name) {
delete val[modules_name][key]
} else {
delete val[key]
}
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(val));
}
}
使用方法:
// console.log(storage.getStorage());
// storage.setItem('a',1);
// storage.setItem('address','北京','person');
// storage.setItem('abc',{data:88},'person');
storage.clear('a')
這樣我們可以將整個專案中使用的storage全部放在一個key/value中,在value中存放所有的data,使用json的形式存盤
1.5 介面錯誤攔截
- 統一報錯
- 未登錄統一攔截
- 請求值,回傳值統一處理
我們通過使用axios的攔截來統一處理請求的情況處理以及對應的回傳值,以及處理未登錄時進行跳轉登錄界面等等,還有統一請求值以及回傳值的處理(比如表單的格式等等),
1.6 介面環境的設定
通常請開個下我們專案再不同的階段有不同的介面
也就是說當我們使用jsonp或者cors跨域的方式來請求介面時,而且我們分環境時會有不同的請求介面,那么我們應該遵循es6模塊化的思想,我們將所有的環境變數進行統一的抽取,而避免在業務代碼中修改我們的代碼而造成一些不可避免的錯誤,
- 開發上線的不同階段,需要不同的配置(也就是說我們不同階段所需要的介面也是不一樣的)
- 不同的跨域方式,配置不同
- 打包的時候通過注入環境引數,統一管理環境,輸出不同的版本包
當我們在代理中使用不同的環境介面怎么辦呢,這時我們就可以直接進行修改vue.config.js的baseurl的可以
一般情況下我們有三套環境,分別是開發,測驗,生產,當我們需要再添加環境時需要我們新建.dev.環境名檔案進行設定NODE_DEV的值,然后再進行回應配置,
? 以下是我們的一個實體:
package.json下
"scripts": {
"serve": "vue-cli-service serve --mode=development",
"test": "vue-cli-service serve --mode=test",
"haha": "vue-cli-service serve --mode=haha",
"build": "vue-cli-service build --mode=production",
},
dev.js模塊(不同環境不同介面的配置):
/*
這是當我們的跨域方式為jsonp或者cors時才能使用的baseURL
不同環境下的BaseURL地址模塊
process.env.NODE_ENV:獲取nodejs行程的一些引數資訊
*/
let baseURL;
switch (process.env.NODE_ENV) {
case 'development':
baseURL = 'http://dev-mall-pre.springboot.cn/api'
break;
case 'test':
baseURL = 'http://test-mall-pre.springboot.cn/api'
break;
case 'haha':
baseURL = 'http://haha-mall-pre.springboot.cn/api'
break;
case 'production':
baseURL = 'http://mall-pre.springboot.cn/api'
break;
default:
baseURL = 'http://mall-pre.springboot.cn/api'
break;
}
export default { baseURL }
自定義環境配置(haha).env.haha檔案:
NODE_ENV='haha'
1.7 MOCK設定
為什么要使用MOCK:
- 開發階段,為了高效率,需要提前Mock
- 減少代碼冗余,靈活插拔
- 減少溝通,減少介面聯調時間
主流的三種MOCK設定:
- 本地創建json
- easy-mock平臺(推薦本地搭建easymock平臺)
- 繼承Mock API(推薦Mock.js)
我們需要注意的是,第一種方式是最簡單,不需要任何學習成本的,當時帶來的弊端就是不能統一介面,也就是說我們需要改的地方比較多,第二種是發送的真實的請求,第三種是攔截請求,在本地模擬資料,后兩種都有一定的學習成本,也推薦使用,
2.首頁功能開發
-
NavHeader開發
-
HeaderFooter
-
首頁輪播圖(Swiper)
-
廣告位
-
商品展示(axios請求)
-
工具model的封裝(使用了Vue影片組件)
-
圖片懶加載 vue-lazyload 插件的使用
3.登錄功能開發
-
登錄注冊界面實作
-
登錄邏輯(設定Cookie快取用戶登錄狀態)
-
注冊邏輯(錯誤攔截的小坑,無法獲取msg資訊,已處理)
疑問:
拉取用戶資訊和購物車數量到Vuex有什么作用,用戶界面重繪Vuex的所有資料都可能清空,拉取這兩條資料有什么本質上的做作用?
解答:
Vuex中只傳輸這兩條資料(因此需要再次拉去一次),自己想太多,以為Vuex中的用戶的資訊和后面的介面請求有關系,其實這里Vuex展示保存了這兩個資料用于再主頁展示而已,
和Cookie的周期搞混亂了,也就是說我們使用這個拉去的前提時我們的狀態時登錄的,所以才會有資料,因此這個解決的就是頁面重繪可能會導致Vuex中的States資料清空,
-
添加Vuex進行首頁用戶名和購物車數量的管理
-
退出登錄功能的實作
-
注冊登錄狀態使用vuex狀態托管
注意點:在index重繪時拉去Vuex中的資料,且在index的宣告周期再次拉去資料,在宣告周期內拉去資料的原因是因為我們使用的是spa模式,因此購物車資料改變并不會重繪,因此我們每次組件進入時再次拉去購物車資料(我認為是有必要的),username可以不采用這種做法
4.產品站功能開發
- 頂部吸頂插件及其功能
- 產品站布局(包括底部的swiper,以及視頻展示)
- 視頻的影片效果
- 介面的請求渲染
5.商品詳情頁面
- 完成界面
- 請求資料進行互動
- 添加購物車跳轉購物車界面
注意:
加入購物車時必須要登錄狀態才可以完成,這里有當時封裝axios時留下的一個坑,就就當狀態為10時,應該回傳reject狀態的promise,
所以當我們未登錄時,點擊添加到購物車,就會執行我們then里面的代碼(Promise如果沒有指定回傳指定狀態會默認回傳resolve狀態),造成一些不必要的bug
6.購物車頁面
- Order-Nav組件的封裝
- 購物車界面
- 購物車介面的請求以一些判斷
總結:再實際開發中,為了預防一些安全問題,購物車的邏輯是由后端完成的,我們前端只需要屬性介面檔案,將各個操作對應即可
7.ElementUI集成
結合官方檔案完成Message等插件的按需加載,提高了開發效率
8.訂單確認功能
- 布局完成
- 初始化互動,渲染當前id的識訓地址、購物車選中的商品資訊等
- 完成識訓地址的洗掉、改變、增加
- 其中使用到了v-distpicker省市級聯動插件,使用方法網上有
- 完成訂單的結算,生成了訂單編號
9.訂單支付功能
-
完成布局
-
實作資料互動
-
支付寶支付(后端傳html的from表單代碼)進行集成
-
微信支付,將后端的支付地址轉為二維碼顯示(Native支付)
-
微信支付輪詢,判斷是否支付(若檢測到用戶已支付則跳轉至訂單串列頁面,關閉則輪詢停止)
微信支付:content內容是支付鏈接,轉換為二維碼即可掃碼支付
支付寶支付:content是html原始碼,渲染到頁面上后自動跳轉到支付頁面
將url轉為二維碼使用QRCode插件,
10.訂單串列功能實作
- 界面實作
- 互動
- 按需引入elementUI分頁器組件并實作分頁功能
- 排查了一些后端介面的錯誤,例如,個人地址資訊介面中的
receiverPhone和支付的介面中的receiverPhone不同步
常見的三種分頁功能:
1.分頁器2.按鈕加載更多
3.滾動加載更多
11.原始碼地址
專案原始碼地址:GitHub傳送門
歡迎學習,歡迎star!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/282127.html
標籤:其他
