Vue+Vue-router+Vuex專案實戰

蟹丸發表於2019-03-19

shopping

vue + vue-router + vuex實現電商網站

效果展示

Vue+Vue-router+Vuex專案實戰

install

  • 下載程式碼: git clone https://github.com/chenchangyuan/shopping.git
  • 安裝依賴: npm install
  • 啟動專案: npm run dev

執行環境: node v9.11.1 npm 5.6.0

需求分析

  1. 登入頁面、商品列表頁(網站首頁)、購物車頁(實現結算)、商品詳情頁
  2. 可按顏色、品牌對商品進行篩選,單擊選中,再次點選取消
  3. 根據價格進行升序降序、銷量降序排列
  4. 商品列表顯示圖片、名稱、銷量、顏色、單價
  5. 實時顯示購物車數量(商品類別數)
  6. 購物車頁面實現商品總價、總數進行結算,優惠券打折

資料儲存 & 資料處理

  • product.js存放商品資料(生產環境需通過介面呼叫獲取資料)
{
	id: 1,
	name: 'AirPods',
	brand: 'Apple',
	image: '/src/images/airPods.jpg',
	imageDetail: '/src/images/airPods_detail.jpg',
	sales: 10000,
	cost: 1288,
	color: '白色'
},
複製程式碼
  • window.localStorage實現資料儲存與驗證
let username = window.localStorage.getItem('username');
let password = window.localStorage.getItem('password');
if(!util.trim(this.username) || !util.trim(this.username) ){
	window.alert('賬號或密碼不能為空');
	return;
}
if(username === this.username && password === this.password){
	this.login = false;
	window.localStorage.setItem('loginStatus', 'login');
	this.$store.commit('getUser', this.username);
	window.alert('登陸成功,確定進入網站首頁');
	window.location.href = '/list';
}else{
	window.alert('賬號或密碼錯誤');
}
複製程式碼

資料過濾與排序處理

filteredAndOrderedList(){
	//拷貝原陣列
	let list = [...this.list];
	//品牌過濾
	if(this.filterBrand !== ''){
		list = list.filter(item => item.brand === this.filterBrand);
	}
	//顏色過濾
	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;
}
複製程式碼

實時顯示應付總額與商品數

//購物車商品總數
countAll(){
	let count = 0;
	this.cartList.forEach(item => {
		count += item.count;
	});
	return count;
},
//購物車商品總價
costAll(){
	let cost = 0;
	this.cartList.forEach(item => {
		cost += this.productDictList[item.id].cost * item.count;
	});
	return cost;
}
複製程式碼

購物車結算處理

//通知Vuex,完成下單
handleOrder(){
	this.$store.dispatch('buy').then(() => {
		window.alert('購買成功');
	})
},
複製程式碼

vue-router & vuex

vue-router路由管理/src/views/目錄下的vue元件進行設定,router-views掛載所有路由,登入介面與商品列表頁面之間header做隱藏顯示處理,登入狀態下重新整理頁面跳轉至列表頁,其他頁面設定預設跳轉

跳轉處理

const router = new VueRouter(RouterConfig);

//跳轉前設定title
router.beforeEach((to, from, next) => {
    window.document.title = to.meta.title;
    next();
});
//跳轉後設定scroll為原點
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: '購物車'
        },
        component: (resolve) => require(['./views/cart.vue'], resolve)
    },
    {
        path: '/login/:loginStatus',
        meta: {
            title: '登入註冊'
        },
        component: (resolve) => require(['./views/login.vue'], resolve)
    },
    {
        path: '*',
        redirect: '/login/login'
    }
];
export default routers;
複製程式碼

vuex狀態管理,各元件共享資料在state中設定,mutation實現資料同步,action非同步載入

//配置Vuex狀態管理
const store = new Vuex.Store({
    state: {
        //商品列表資訊
        productList: [],
        //購物車資料,陣列形式,資料元素為物件(商品id,購買數量count)
        cartList: [],
        //當前使用者賬號
        username: window.localStorage.getItem('username'),
        //登入狀態
        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;
        },
        //新增購物車
        addCart(state, id){
            const isAdded = state.cartList.find(item => item.id === id);
            //如果不存在設定購物車為1,存在count++
            if(isAdded){
                isAdded.count++;
            }else{
                state.cartList.push({
                    id: id,
                    count: 1
                })
            }
        },
		//修改購物車商品數量
        editCartCount(state, payload){
            const product = state.cartList.find(item => item.id === payload.id);
            product.count += payload.count;
        },
        //刪除購物車商品
        deleteCart(state, id){
            const index = state.cartList.findIndex(item => item.id === id);
            state.cartList.splice(index, 1)
        },
        //清空購物車
        emptyCart(state){
            state.cartList = [];
        },
        getUser(state, username){
            console.log('username',username)
            state.username = username;
        },
        getLoginStatus(state, flag){
            state.loginStatus = flag;
        }
    },
	actions: {
        //非同步請求商品列表,暫且使用setTimeout
        getProductList(context){
            setTimeout(() => {
                context.commit('setProductList', product_data)
            }, 500);
        },
        //購買
        buy(context){
            //生產環境使用ajax請求服務端響應後再清空購物車
            return new Promise(resolve => {
                setTimeout(() => {
                    context.commit('emptyCart');
                    resolve();
                }, 500);
            });
        },
    }
});
複製程式碼

後記

專案地址: 閱讀完本文如果對vue的理解有所幫助,請給顆star,謝謝~

筆者個人微信 gm4118679254 歡迎加好友一起交流技術

參考資料

Vue.js實戰 Vue.js

相關文章