shopping
vue
+ vue-router
+ vuex
實(shí)現(xiàn)電商網(wǎng)站
效果展示
install
- 下載代碼:
git clone https://github.com/chenchangyuan/shopping.git
- 安裝依賴(lài):
npm install
- 啟動(dòng)項(xiàng)目:
npm run dev
運(yùn)行環(huán)境: node v9.11.1 npm 5.6.0
需求分析
- 登錄頁(yè)面蹬屹、商品列表頁(yè)(網(wǎng)站首頁(yè))侧漓、購(gòu)物車(chē)頁(yè)(實(shí)現(xiàn)結(jié)算)昔榴、商品詳情頁(yè)
- 可按顏色畅蹂、品牌對(duì)商品進(jìn)行篩選,單擊選中,再次點(diǎn)擊取消
- 根據(jù)價(jià)格進(jìn)行升序降序、銷(xiāo)量降序排列
- 商品列表顯示圖片、名稱(chēng)闯冷、銷(xiāo)量、顏色懈词、單價(jià)
- 實(shí)時(shí)顯示購(gòu)物車(chē)數(shù)量(商品類(lèi)別數(shù))
- 購(gòu)物車(chē)頁(yè)面實(shí)現(xiàn)商品總價(jià)蛇耀、總數(shù)進(jìn)行結(jié)算,優(yōu)惠券打折
數(shù)據(jù)存儲(chǔ) & 數(shù)據(jù)處理
-
product.js
存放商品數(shù)據(jù)(生產(chǎn)環(huán)境需通過(guò)接口調(diào)用獲取數(shù)據(jù))
{
id: 1,
name: 'AirPods',
brand: 'Apple',
image: '/src/images/airPods.jpg',
imageDetail: '/src/images/airPods_detail.jpg',
sales: 10000,
cost: 1288,
color: '白色'
},
-
window.localStorage
實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)與驗(yàn)證
let username = window.localStorage.getItem('username');
let password = window.localStorage.getItem('password');
if(!util.trim(this.username) || !util.trim(this.username) ){
window.alert('賬號(hào)或密碼不能為空');
return;
}
if(username === this.username && password === this.password){
this.login = false;
window.localStorage.setItem('loginStatus', 'login');
this.$store.commit('getUser', this.username);
window.alert('登陸成功坎弯,確定進(jìn)入網(wǎng)站首頁(yè)');
window.location.href = '/list';
}else{
window.alert('賬號(hào)或密碼錯(cuò)誤');
}
數(shù)據(jù)過(guò)濾與排序處理
filteredAndOrderedList(){
//拷貝原數(shù)組
let list = [...this.list];
//品牌過(guò)濾
if(this.filterBrand !== ''){
list = list.filter(item => item.brand === this.filterBrand);
}
//顏色過(guò)濾
if(this.filterColor !== ''){
list = list.filter(item => item.color === this.filterColor);
}
//排序
if(this.order !== ''){
if(this.order === 'sales'){
list = list.sort((a, b) => b.sales - a.sales);
}else if(this.order === 'cost-desc'){
list = list.sort((a, b) => b.cost - a.cost);
}else if(this.order === 'cost-asc'){
list = list.sort((a, b) => a.cost - b.cost);
}
}
return list;
}
實(shí)時(shí)顯示應(yīng)付總額與商品數(shù)
//購(gòu)物車(chē)商品總數(shù)
countAll(){
let count = 0;
this.cartList.forEach(item => {
count += item.count;
});
return count;
},
//購(gòu)物車(chē)商品總價(jià)
costAll(){
let cost = 0;
this.cartList.forEach(item => {
cost += this.productDictList[item.id].cost * item.count;
});
return cost;
}
購(gòu)物車(chē)結(jié)算處理
//通知Vuex,完成下單
handleOrder(){
this.$store.dispatch('buy').then(() => {
window.alert('購(gòu)買(mǎi)成功');
})
},
vue-router & vuex
vue-router路由管理/src/views/
目錄下的vue
組件進(jìn)行設(shè)置纺涤,router-views
掛載所有路由,登錄界面與商品列表頁(yè)面之間header做隱藏顯示處理抠忘,登錄狀態(tài)下刷新頁(yè)面跳轉(zhuǎn)至列表頁(yè)撩炊,其他頁(yè)面設(shè)置默認(rèn)跳轉(zhuǎn)
跳轉(zhuǎn)處理
const router = new VueRouter(RouterConfig);
//跳轉(zhuǎn)前設(shè)置title
router.beforeEach((to, from, next) => {
window.document.title = to.meta.title;
next();
});
//跳轉(zhuǎn)后設(shè)置scroll為原點(diǎn)
router.afterEach((to, from, next) => {
window.scrollTo(0, 0);
});
routers配置
//商品列表路由配置
const routers = [
{
path: '/list',
meta: {
title: '商品列表'
},
component: (resolve) => require(['./views/list.vue'], resolve)
},
{
path: '/product/:id',
meta: {
title: '商品詳情'
},
component: (resolve) => require(['./views/product.vue'], resolve)
},
{
path: '/cart',
meta: {
title: '購(gòu)物車(chē)'
},
component: (resolve) => require(['./views/cart.vue'], resolve)
},
{
path: '/login/:loginStatus',
meta: {
title: '登錄注冊(cè)'
},
component: (resolve) => require(['./views/login.vue'], resolve)
},
{
path: '*',
redirect: '/login/login'
}
];
export default routers;
vuex狀態(tài)管理,各組件共享數(shù)據(jù)在state
中設(shè)置崎脉,mutation
實(shí)現(xiàn)數(shù)據(jù)同步拧咳,action
異步加載
//配置Vuex狀態(tài)管理
const store = new Vuex.Store({
state: {
//商品列表信息
productList: [],
//購(gòu)物車(chē)數(shù)據(jù),數(shù)組形式囚灼,數(shù)據(jù)元素為對(duì)象(商品id骆膝,購(gòu)買(mǎi)數(shù)量count)
cartList: [],
//當(dāng)前用戶賬號(hào)
username: window.localStorage.getItem('username'),
//登錄狀態(tài)
loginStatus: !!window.localStorage.getItem('loginStatus'),
},
getters: {
//品牌、顏色篩選
brands: state => {
const brands = state.productList.map(item => item.brand);
return util.getFilterArray(brands);
},
colors: state => {
const colors = state.productList.map(item => item.color);
return util.getFilterArray(colors);
}
},
//mutations只能以同步方式
mutations: {
//添加商品列表
setProductList(state, data){
state.productList = data;
},
//添加購(gòu)物車(chē)
addCart(state, id){
const isAdded = state.cartList.find(item => item.id === id);
//如果不存在設(shè)置購(gòu)物車(chē)為1灶体,存在count++
if(isAdded){
isAdded.count++;
}else{
state.cartList.push({
id: id,
count: 1
})
}
},
//修改購(gòu)物車(chē)商品數(shù)量
editCartCount(state, payload){
const product = state.cartList.find(item => item.id === payload.id);
product.count += payload.count;
},
//刪除購(gòu)物車(chē)商品
deleteCart(state, id){
const index = state.cartList.findIndex(item => item.id === id);
state.cartList.splice(index, 1)
},
//清空購(gòu)物車(chē)
emptyCart(state){
state.cartList = [];
},
getUser(state, username){
console.log('username',username)
state.username = username;
},
getLoginStatus(state, flag){
state.loginStatus = flag;
}
},
actions: {
//異步請(qǐng)求商品列表阅签,暫且使用setTimeout
getProductList(context){
setTimeout(() => {
context.commit('setProductList', product_data)
}, 500);
},
//購(gòu)買(mǎi)
buy(context){
//生產(chǎn)環(huán)境使用ajax請(qǐng)求服務(wù)端響應(yīng)后再清空購(gòu)物車(chē)
return new Promise(resolve => {
setTimeout(() => {
context.commit('emptyCart');
resolve();
}, 500);
});
},
}
});
后記
項(xiàng)目地址: 閱讀完本文如果對(duì)vue的理解有所幫助,請(qǐng)給顆star赃春,謝謝~
筆者個(gè)人微信 gm4118679254
歡迎加好友一起交流技術(shù)