1. 程式人生 > >Vue+vuex+vue-router+sass+webpack+mint-ui 全家桶 開發商城(購物車)

Vue+vuex+vue-router+sass+webpack+mint-ui 全家桶 開發商城(購物車)

先上截圖,專案跑起來就是這個樣子,是不是符合你的購物車?哈哈哈哈哈哈哈,我就知道



購物車實現的功能:新增購物車、選擇某商家下所有商品、選擇指定商品、更新指定商品數量(加減)、刪除指定商品、全選商品、清空購物車,等功能;

準備工作:

使用Vue全家桶(vue2.0+vue-router+vuex+webpack+sass+mint-ui),由於都是靜態資料,就沒有使用axios;

注:通常使用npm安裝會出現以下報錯,安裝失敗。(網路問題)

可以通過淘寶的npm映象安裝node-sass,解決以上問題。

$ npm install -g cnpm --registry=https://registry.npm.taobao.org  (安裝淘寶映象)

安裝 vue-cli:

cnpm install -g vue-cli  //全域性安裝vue-cli;
vue init webpack User //User為專案名稱
cd User //進入User專案
cnpm install //安裝依賴
npm run dev //執行專案
此時專案 基本執行起來,在瀏覽器輸入:http://localhost:8080

安裝vue-router,vuex,sass,mint-ui

cnpm install vue-router --save //安裝路由cnpm install vuex -S //暗轉vuexcnpm install node-sass --save-dev //安裝node-sass環境cnpm install sass-loader --save-dev //安裝sass-loader
cnpm install mint-ui --save //安裝mint-ui

到這裡基本安裝完成,然後在User->src資料夾中建立 store,router,view資料夾,在store,router,view檔案裡建立如下目錄

      

下面來修改main.js 檔案:main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import VueRouter from 'vue-router' import axios from 'axios' import App from './App' import routes from './router'//匯入註冊路由表 import store from './store'//匯入vuex import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' import '@/assets/css/reset.css' Vue.config.productionTip = false Vue.use(MintUI) Vue.use(VueRouter) Vue.prototype.$ajax = axios const router = new VueRouter({ routes }) router.beforeEach(({meta, path}, from, next) => { var { auth = true } = meta var isLogin = Boolean(store.state.user.phone) //true使用者已登入, false使用者未登入 console.log('isLogin:'+isLogin+',,,auth:'+auth+',,,path:'+path) if (!auth && !isLogin && path !== '/login') { return next({ path: '/login' }) } next() }) /* eslint-disable no-new */ new Vue({ router, store, render: h => h(App) }).$mount('#app')
  現在編寫路由登錄檔 :router->index.js
import Vue from 'vue'
// import Router from 'vue-router'
// import index from '@/components/index'
import main from '@/views/main'
import mainpage from '@/views/barItem/mainpage'
import productList from '@/views/barItem/productList'
import shopping from '@/views/barItem/shopping'
import usercenter from '@/views/barItem/usercenter'
import details from '@/views/details/details'
import seller from '@/views/seller/seller'
import classy from '@/views/classy/classy'
import login from '@/views/login/login'
// Vue.use(Router)
export default [
  {
path: '/',
name: 'main',
component: main,
children:[
      {
path:'/',
name:'精選',
component:mainpage
      },
{
path:'/productList',
name:'逛逛',
component:productList
      },
{
path:'/shopping',
name:'購物車',
meta: { auth: false },
component:shopping
      },
{
path:'/usercenter',
name:'我的',
component:usercenter
      },
]
  },
{
path:'/details',
name:'產品詳情',
component:details
  },
{
path:'/classy',
name:'分類',
component:classy
  },
{
path:'/seller',
name:'賣家主頁',
component:seller
  },
{
path:'/login',
name:'登入',
component:login
  },
{
path: '*', //其他頁面,強制跳轉到登入頁面
redirect: '/login'
}
]

現在編寫重中之重的就是,store狀態管理了

在store->modeles檔案下,有兩個js檔案,解釋下:user.js是儲存登入狀態,cart.js是儲存購物車狀態;(一波強加解釋.......);

store->index.js(這裡不做太多解釋了):

import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'//匯入user
import cart from './modules/cart'//匯入購物車
Vue.use(Vuex)//使用vuex
export default new Vuex.Store({
modules: {
user,
cart
  },
strict: process.env.NODE_ENV !== 'production', //在非生產環境下,使用嚴格模式
})

store->modeles->user.js:

import Vue from 'vue'
export const USER_SIGNIN = 'USER_SIGNIN' //登入成功
export const USER_SIGNOUT = 'USER_SIGNOUT' //退出登入
export default {
state: JSON.parse(sessionStorage.getItem('user')) || {},
mutations: {
    [USER_SIGNIN](state, user) {
sessionStorage.setItem('user', JSON.stringify(user))
Object.assign(state, user)//Object.assign() 方法用於將所有可列舉屬性的值從一個或多個源物件複製到目標物件。它將返回目標物件。
},
[USER_SIGNOUT](state) {
sessionStorage.removeItem('user')
Object.keys(state).forEach(k => Vue.delete(state, k))//Object.keys() 方法會返回一個由一個給定物件的自身可列舉屬性組成的陣列,陣列中屬性名的排列順序和使用 for...in 迴圈遍歷該物件時返回的順序一致 (兩者的主要區別是 一個 for-in 迴圈還會列舉其原型鏈上的屬性)。
}
  },
actions: {
    [USER_SIGNIN]({commit}, user) {
commit(USER_SIGNIN, user)
    },
[USER_SIGNOUT]({commit}) {
commit(USER_SIGNOUT)
    }
  }
}

store->modeles->cart.js

//初始化資料
const state = {
detailsData:{},//臨時儲存詳情頁資訊
addCart:[]//新增到購物車的商品(已選商品)
}
//getter 丟擲去的資料
const getters ={
//獲取詳情頁資訊
getDetails:state => {
return state.detailsData
  },
//購物車的列表
cartDataList:state =>{
console.log(state.addCart)
return state.addCart;
},
//計算總價
totalPrice:(state,getters) => {
let total = 0;
getters.cartDataList.map(//遍歷所有商家
item => {
item.goodsList.map((n) => {//遍歷該商家下所有商品
if(n.checked === true){//篩選選中的商品
            //---------這裡可以新增運費,減免運費的等條件-------------
total += n.goodsInfo.price * n.number;//計算所有選中商品價格*數量,相加
}
        });
}
    );
    return total;
},
//計算選中商品總數量
totalNum:(state,getters) => {
let total = 0;
getters.cartDataList.map(
item => {
item.goodsList.map((n) => {//遍歷該商家下所有商品
if(n.checked === true){//篩選選中的商品
total += n.number//計算所有選中商品數量,相加
}
        });
}
    );
    return total;
},
//提交按鈕是否被啟用
isActive:(state,getters) => {
let active = true;
getters.cartDataList.map(item => {
active = item.goodsList.find(n => n.checked === true );
})
return active;
}
}
//action 非同步的操作
const actions = {
//設定詳情頁資訊
setDetails({commit},item){
commit('setDetails',{item})
  },
//新增購物車
addToCart({commit},item){
commit('addToCart',{item})
  },
//修改全選狀態
setSelectAll({commit},val){
commit('setSelectAll',val)
  },
//選擇商家下所有商品
checkedShop({commit},id){
commit('checkedShop',id)
  },
//選擇某一件商品
checkedGodds({commit},item){
commit('checkedGodds',item)
  },
//更新某一件商品數量
updateGoods({commit},item){
commit('updateGoods',{item})
  },
//刪除某一件商品
delGodds({commit},item){
commit('delGodds',{item})
  },
//清空購物車
clearAllCart({commit}){
commit('clearAllCart')
  }
}
//mutations 同步的操作
const mutations = {
//設定詳情頁資訊
setDetails(state,item){
state.detailsData = item;
},
//新增購物車方法
addToCart(state,{item}){//當接受的引數為物件時用{},字串時不用{}
let recordAdmin = state.addCart.find(n => n.adminId === item.adminId);//遍歷購物車是否存在該商家
if(!recordAdmin){//購物車不存在該商家
state.addCart.push({//在陣列首部插入,確保新加入購物車的商品在購物車列表最上部顯示
adminId:item.adminId,//商家ID
adminName:item.adminName,//商家名稱
adminAvatar:item.avatar,//商家頭像
shopChecked:true,//店鋪全選
goodsList:[
          {
id:item.id,//商品
checked:true,//商品是否被選中
goodsInfo:item,//商品詳情
number:1//新增數量
}
        ]
      })
    }else{//購物車已存在該商家
let recordProduct = recordAdmin.goodsList.find(n => n.id === item.id);//遍歷是否存在該商品
if(!recordProduct){//購物車不存在該商品
recordAdmin.goodsList.push(
          {
id:item.id,//商品
checked:true,//商品是否被選中
goodsInfo:item,//商品詳情
number:1//新增數量
}
        )
      }else{//購物車存在該商品
recordProduct.checked = true;//商品是否被選中
recordProduct.number++
}
console.log(recordAdmin)
    }
console.info(state.addCart)
  },
//修改全選狀態
setSelectAll(state,val){
state.addCart.map(item => {//遍歷所有商家
item.shopChecked = val;//修改該商家選中狀態
item.goodsList.map(n => {//遍歷該商家下所有商品
n.checked = val;//修改該商品選中狀態
})
    })
  },
//選擇商家
checkedShop(state,id){
let shopItem = state.addCart.find(n => n.adminId === id);//獲取(adminID===item.shopId)商家
shopItem.goodsList.map((n) => {//遍歷該商家下所有商品
if(!shopItem.shopChecked){//商家下商品全選
n.checked != true ? n.checked = !n.checked : '';//已選中的商品不執行
}else{
n.checked = false;
}
    });
shopItem.shopChecked = !shopItem.shopChecked;//修改商家選中狀態
},
//選擇商品
checkedGodds(state,item){
let shopItem = state.addCart.find(n => n.adminId === item.shopId);//獲取(adminID===item.shopId)商家
let goodsItem = shopItem.goodsList.find(n => n.id === item.goodsId);//該商家下(id===item.goodsId)的商品
goodsItem.checked = !goodsItem.checked;//修改商品選中狀態
let shopChecked = shopItem.goodsList.find(n => n.checked === false);//檢視該商家下是否有沒有選中的商品
if(!shopChecked){//沒有未選中的商品
shopItem.shopChecked = true;//將該商家選中狀態
}else{
shopItem.shopChecked = false;
}
  },
//更新商品數量
updateGoods(state,item){
let shopItem = state.addCart.find(n => n.adminId === item.shopId);//獲取(adminID===item.shopId)商家
let goodsItem = shopItem.goodsList.find(n => n.id === item.goodsId);//該商家下(id===item.goodsId)的商品
goodsItem.number = goodsItem.number+item.value < 1 ?1 : goodsItem.number+item.value;//修改該商品數量
},
//刪除購物車指定商品
delGodds(state,item){
let shopItemIndex = state.addCart.findIndex(n => n.adminId === item.shopId);//獲取(adminID===item.shopId)商家index
let goodsItemIndex = state.addCart[shopItemIndex].goodsList.findIndex(n => n.id === item.goodsId);//該商家下(id===item.goodsId)的商品index
state.addCart[shopItemIndex].goodsList.splice(goodsItemIndex,1);//刪除該商家該商品
if(!state.addCart[shopItemIndex].goodsList.length){//商品為空,刪除該商家
state.addCart.splice(shopItemIndex,1);
}
  },
//清空購物車
clearAllCart(state){
state.addCart = []
  }
}
export default {
state,
mutations,
actions,
getters
}

到這裡基本的都完成了,剩下的就是元件呼叫 vuex裡的方法了(只上乾貨,下面我會附上原始碼):

登入功能:

import {mapActions} from 'vuex'
import {USER_SIGNIN} from '@/store/modules/user'
export default {
data(){
return{
form:{
phone:'',
password:''
}
    }
  },
methods:{
...mapActions([USER_SIGNIN]),
submit() {
this.btn = true
      if(!this.form.phone || !this.form.password) return
      this.USER_SIGNIN(this.form)
this.$router.replace({ path: '/' })
    }
  }
}

退出登入:

import {mapActions} from 'vuex'
import {USER_SIGNOUT} from '@/store/modules/user'
export default {
name: 'hello',
data () {
return {}
  },
methods: {
...mapActions([USER_SIGNOUT]),
sigout:function(){
console.log('退出登入')
this.USER_SIGNOUT()
this.$router.replace({ path: '/usercenter/login' })
    }  }
}

購物車頁面:

import {mapGetters,mapMutations} from 'vuex'
export default {
data(){
return{
    }
  },
computed:{
...mapGetters(['cartDataList','totalPrice','totalNum','isActive']),//cartDataList:購物車列表;totalPrice:購物車總價;totalNum:確定購買數量;isActive:按鈕是否被啟用
    //全選按鈕
selectAll: {
//獲取是否全選
get: function () {
return this.cartDataList.filter(function (items) { //動態判斷全選按鈕是否選中(根據 選中的商店數量==items陣列長度)
return items.shopChecked === true;
}).length == this.cartDataList.length;
},
//修改全選按鈕狀態
set: function (val) {
this.setSelectAll(val);//呼叫methods中setSelectAll方法,修改vuex中所有商家和商品選中狀態
}
    }
  },
methods:{
...mapMutations(['setSelectAll','checke