先上截图,项目跑起来就是这个样子,是不是符合你的购物车?哈哈哈哈哈哈哈,我就知道
购物车实现的功能:添加购物车、选择某商家下所有商品、选择指定商品、更新指定商品数量(加减)、删除指定商品、全选商品、清空购物车,等功能;
准备工作:
注:通常使用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 //运行项目
cnpm install vue-router --save //安装路由
cnpm install vuex -S //暗转vuex
cnpm install node-sass --save-dev //安装node-sass环境
cnpm install sass-loader --save-dev //安装sass-loader
cnpm install mint-ui --save //安装mint-ui
// 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','checkedShop','checkedGodds','updateGoods','delGodds','clearAllCart']), //选择商家 selectedShop(adminId){ this.checkedShop(adminId) }, //选择商品 selectedGoods(shopId,goodsId){ let item = { shopId:shopId,//商家id goodsId:goodsId//商品id } this.checkedGodds(item) }, //更新指定商品数量,加减 update(n,shopId,goodsId){ let item = { value:n,//改变数值 shopId:shopId,//商家id goodsId:goodsId//商品id }; console.log(item) this.updateGoods(item); }, //删除指定商品 delBtn(shopId,goodsId){ this.$messageBox.confirm('确定执行此操作?').then(action => { let item = { shopId:shopId,//商家id goodsId:goodsId//商品id } console.info(item) this.delGodds(item) }); }, //清空购物车 clearCart(){ this.clearAllCart(); }, //结算按钮 submitBtn(isActive){ console.log(isActive) } } }
想看源码的小朋友,看这里:https://github.com/jianjiayi/User 点击打开链接