通常,我们做移动端商城的时候,通常会有购物车模块,那购物车模块有两种实现方式,一是储存在后台通过接口获取到购物车信息,二是存在用户手机本地,第一种方法只要调用接口获取比较简单,这里介绍的是第二种方法,利用vuex将购物车数据存在本地的方法。

vue项目创建方法和vuex的写法之前博文都有介绍,这里就不再重复了;

vant安装:

# 通过 npm 安装
npm i vant -S # 通过 yarn 安装
yarn add vant

具体使用方法请去它的官网了解

地址:https://youzan.github.io/vant/#/zh-CN/

购物车页面编写和本地的价格计算:

1.我们把vant按需引入,我们用到了Icon, Checkbox, Stepper, SubmitBar, Toast这些组件;

2.为了方便复制即用,我在本地写了一些购物车死数据goods用于渲染;

3.虽说是把商品信息购物车存在本地,实际上我们只需要存商品id和商品数量num;

4.我们需要通过单选的change事件,全选事件,步进器增加减少进行价格换算;

为了方便复制粘贴直接看效果,直接上demo

demo.html

<template>
<div class="shopCart">
<div class="cartList">
<ul v-if="goods.length > 0">
<li v-for="item in goods" :key="item.id">
<van-checkbox
:value="item.id"
v-model="item.isChecked"
checked-color="#15C481"
@click="chooseChange(item.id, item)"
></van-checkbox>
<div class="shopdetail">
<div class="detailimg">
<img :src="item.thumb" />
</div>
<div class="detailtext">
<div class="shoptitle van-multi-ellipsis--l2">
{{ item.title }}
</div>
<div class="shoppricenum">
<p class="shopprice">
¥{{ item.price
}}{{ item.lvd > 0 ? "+" + item.lvd + "LVD" : "" }}
</p>
<div class="shopnum">
<van-stepper v-model="item.num" @change="onChange(item)" />
</div>
</div>
</div>
</div>
</li>
</ul>
<div class="nohaveshop" v-else>
<van-icon name="shopping-cart-o" />
<p class="p1">你的购物车空空如也~~</p>
<p class="p2">快去采购吧!</p>
</div>
</div>
<div class="cartfotter" v-if="goods.length > 0">
<van-submit-bar button-text="去结算" @submit="onSubmit">
<van-checkbox
v-model="allchecked"
checked-color="#15C481"
@click="checkAll"
>全选</van-checkbox
>
<div class="buyprice">
<p class="p1">合计</p>
<p class="p2">
¥{{ totalprice }}{{ totallvd > 0 ? "+" + totallvd + "LVD" : "" }}
</p>
</div>
</van-submit-bar>
</div>
</div>
</template> <script>
import { Icon, Checkbox, Stepper, SubmitBar, Toast } from "vant";
export default {
components: {
[Icon.name]: Icon,
[Checkbox.name]: Checkbox,
[Stepper.name]: Stepper,
[SubmitBar.name]: SubmitBar,
[Toast.name]: Toast
},
data() {
return {
goods: [
{
id: 1,
title: "Zoneid 2019 新款羊羔绒蓝白拼接立领夹克男 9.9成新",
price: 980,
lvd: 12,
num: 1,
thumb:
"https://img.yzcdn.cn/public_files/2017/10/24/2f9a36046449dafb8608e99990b3c205.jpeg"
},
{
id: 2,
title: "青春女装复古时尚保暖拼接翻领夹克",
price: 1200,
lvd: 0,
num: 2,
thumb:
"https://img.yzcdn.cn/public_files/2017/10/24/f6aabd6ac5521195e01e8e89ee9fc63f.jpeg"
},
{
id: 3,
title: "成熟男装新款西装立体拼接立领夹克和正装",
price: 1000,
lvd: 8,
num: 1,
thumb:
"https://img.yzcdn.cn/public_files/2017/10/24/320454216bbe9e25c7651e1fa51b31fd.jpeg"
}
],
allchecked: false,
selectedData: [],
// 总价
totalprice: 0,
totallvd: 0
};
},
created: function() {
this.count();
},
computed: {},
methods: {
// 单选的change事件
chooseChange(i, item) {
Toast(i);
if (this.selectedData.indexOf(i) > -1) {
console.log(i);
var arrs = this.selectedData.filter(function(item) {
return item != i;
});
this.selectedData = arrs;
item.isChecked = false;
// this.remove(this.selectedData, i);
this.count();
console.log(this.selectedData);
} else {
this.selectedData.push(i);
item.isChecked = true;
this.count();
}
if (this.selectedData.length < this.goods.length) {
this.allchecked = false;
} else {
this.allchecked = true;
}
this.count();
console.log(this.selectedData);
},
// 商品数量
onChange(item) {
Toast(item.num);
this.count();
console.log(this.goods);
},
// 计算价格
count: function() {
var totalPrice = 0; //临时总价
var totalLvd = 0; //临时lvd
this.goods.forEach(function(val) {
if (val.isChecked) {
totalPrice += val.num * val.price; //累计总价
totalLvd += val.num * val.lvd; //累计lvd
}
});
this.totalprice = totalPrice;
this.totallvd = totalLvd;
},
// 全选
checkAll() {
let list = this.goods;
if (this.allchecked === true) {
list.forEach(element => {
element.isChecked = false;
});
this.selectedData = [];
this.count();
console.log("111" + this.selectedData);
} else {
list.forEach(element => {
element.isChecked = true;
if (this.selectedData.indexOf(element.id) < 0) {
this.selectedData.push(element.id);
}
});
this.count();
console.log("222" + this.selectedData);
}
},
// 去结算
onSubmit() {
// 选择购买的商品
var cartgoods = [];
this.goods.forEach(function(item) {
if (item.isChecked) {
cartgoods.push({ id: item.id, num: item.num });
}
});
if (cartgoods.length === 0) {
Toast("请选择商品购买");
} else {
this.$router.push("shopBuy");
}
console.log(cartgoods);
}
}
};
</script> <style lang="scss" scoped>
.shopCart {
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
background-color: #f6f6f6;
.cartList {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 16px;
ul {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 100px;
li {
width: 100%;
height: 96px;
background-color: #fff;
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 12px;
.van-checkbox {
margin-left: 17px;
::v-deep .van-checkbox__icon {
height: 14px;
line-height: 14px;
.van-icon {
width: 14px;
height: 14px;
font-size: 12px;
border: 1px solid #a5a5a5;
}
}
}
.shopdetail {
display: flex;
flex-direction: row;
align-items: center;
margin-left: 13px;
.detailimg {
width: 64px;
height: 64px;
background: rgba(165, 165, 165, 1);
border-radius: 4px;
img {
width: 100%;
height: 100%;
border-radius: 4px;
}
}
.detailtext {
width: 230px;
height: 60px;
display: flex;
flex-direction: column;
margin-left: 8px;
position: relative;
.shoptitle {
width: 180px;
text-align: justify;
font-size: 12px;
color: #212121;
line-height: 17px;
}
.shoppricenum {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
position: absolute;
bottom: 0px;
.shopprice {
font-size: 12px;
color: #15c481;
font-weight:;
}
.shopnum {
display: flex;
::v-deep .van-stepper {
button {
width: 14px;
height: 14px;
border: 1px solid #333333;
border-radius: 50px;
background-color: #fff;
}
.van-stepper__minus::before {
width: 8px;
}
.van-stepper__plus::before {
width: 8px;
}
.van-stepper__plus::after {
height: 8px;
}
.van-stepper__input {
font-size: 12px;
color: #333333;
background-color: #fff;
padding: 0px 12px;
}
}
}
}
}
}
}
}
.nohaveshop {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 100px;
.van-icon {
font-size: 60px;
color: #666;
}
p {
font-size: 14px;
color: #999;
}
.p1 {
margin-top: 20px;
}
}
}
.cartfotter {
width: 100%;
height: 60px;
position: fixed;
bottom:;
left:;
.van-submit-bar__bar {
height: 60px;
font-size: 16px;
.van-checkbox {
margin-left: 17px;
::v-deep .van-checkbox__icon {
height: 14px;
line-height: 14px;
.van-icon {
width: 14px;
height: 14px;
font-size: 12px;
border: 1px solid #a5a5a5;
}
}
::v-deep .van-checkbox__label {
font-size: 16px;
color: #212121;
margin-left: 9px;
}
}
.buyprice {
flex:;
padding-right: 8px;
text-align: right;
display: flex;
flex-direction: column;
.p1 {
font-size: 10px;
color: #001410;
}
.p2 {
font-size: 12px;
color: #15c481;
margin-top: 4px;
}
}
.van-button--danger {
width: 130px;
height: 60px;
background: rgba(21, 196, 129, 1);
border: none;
font-size: 16px;
color: #ffffff;
}
}
}
}
</style>

上面代码没用到vuex,目的是方便复制在进去就能直接运行,上面代码同样适用于接口获取购物车的情况,进行本地价格计算,vuex我在下面分开介绍,按需添加进去;

store下的index.js

import Vue from "vue";
import Vuex from "vuex";
import app from "@/store/module/cart";
Vue.use(Vuex); export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {
cart
}
});

上方代码我们创建了一个cart,专门用于购物车模块;

cart.js

export default {
state: {
// 购物车
cartGoods: []
},
getters: {
cartGoodIds(state) {
return state.cartGoods.map(item => item.productId);
}
},
mutations: {
INIT_CART(state) {
if (localStorage && localStorage.getItem("cartGoods")) {
const goods = JSON.parse(localStorage.getItem("cartGoods"));
state.cartGoods = goods;
}
},
ADD_TO_CART(state, addGood) {
const findGood = state.cartGoods.find(
item => item.productId === addGood.productId
);
if (findGood) {
findGood.num = findGood.num + addGood.num;
} else {
state.cartGoods.push(addGood);
}
if (localStorage) {
localStorage.setItem("cartGoods", JSON.stringify(state.cartGoods));
}
},
INPUT_TO_CART(state, inpGood) {
const findGood = state.cartGoods.find(
item => item.productId === inpGood.productId
);
const largeGood = state.cartGoods.find(item => item.num > inpGood.num);
const equalGood = state.cartGoods.find(item => item.num == inpGood.num);
const smallGood = state.cartGoods.find(item => item.num < inpGood.num);
if (findGood && largeGood) {
findGood.num = findGood.num - (findGood.num - inpGood.num);
}
if (findGood && equalGood) {
findGood.num = inpGood.num;
}
if (findGood && smallGood) {
findGood.num = inpGood.num;
}
if (localStorage) {
localStorage.setItem("cartGoods", JSON.stringify(state.cartGoods));
}
}
}
};

上方我们定义了一些计算方法和事件方法,来在其他页面调用时改变购物车储存的信息;

其他页面:

// 导入
import { mapGetters, mapMutations } from "vuex";
// 计算
computed: {
...mapGetters(["cartGoodIds"])
},
// 方法
methods: {
...mapMutations(["ADD_TO_CART", "INPUT_TO_CART", "INIT_CART"]),
}
// 使用
// 增加
// 增加
plusadd(item) {
this.$store.commit("ADD_TO_CART", {
productId: item.id,
num: 1
});
},
// 减少
minuscut(item) {
this.$store.commit("ADD_TO_CART", {
productId: item.id,
num: -1
});
},
// 输入
blurinput(item) {
this.$store.commit("INPUT_TO_CART", {
productId: item.id,
num: parseInt(item.num)
});
},

就先粗略的介绍到这里,有什么问题提出来我及时改正,谢谢!

Vue+Vant+Vuex实现本地购物车功能的更多相关文章

  1. 利用Vue实现一个简单的购物车功能

    开始学习Vue的小白,dalao多多指正 想要实现下面这个界面,包含总价计算.数量增加和移除功能 话不多说代码如下 <!DOCTYPE html> <html> <hea ...

  2. 基于vue2.0打造移动商城页面实践 vue实现商城购物车功能 基于Vue、Vuex、Vue-router实现的购物商城(原生切换动画)效果

    基于vue2.0打造移动商城页面实践 地址:https://www.jianshu.com/p/2129bc4d40e9 vue实现商城购物车功能 地址:http://www.jb51.net/art ...

  3. vue实战记录(五)- vue实现购物车功能之商品总金额计算和单选全选删除功能

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(五) GitHub:sue ...

  4. vue实战记录(六)- vue实现购物车功能之地址列表选配

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(六) GitHub:sue ...

  5. vue实战记录(四)- vue实现购物车功能之过滤器的使用

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(四) GitHub:sue ...

  6. vue实战记录(三)- vue实现购物车功能之渲染商品列表

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(三) GitHub:sue ...

  7. vue实战记录(二)- vue实现购物车功能之创建vue实例

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(二) GitHub:sue ...

  8. vue实战记录(一)- vue实现购物车功能之前提准备

    vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(一) GitHub:sue ...

  9. 用Vue来实现购物车功能(二)

    这个小demo具有添加商品进购物车 .增加购物车内商品的数量.减少购物车内商品的数量.计算一类商品的总价.以及计算所有商品的总价 首先看目录结构 因为我们的Tab.vue  Car.vue 以及Car ...

随机推荐

  1. php实现第三方登录

    1. oAuth2.0原理 网站为了方便用户快速的登录系统,都会提供使用知名的第三方平台账号进行快速登录的功能,第三方登录都是基于oAuth2.0标准来实现的.下面详细分析[基于账号密码授权]和[基于 ...

  2. angular ui 路由传参

    1. ui-sref.$state.go 的区别 ui-sref 一般使用在 <a>...</a>: $state.go('someState')一般使用在 controlle ...

  3. PHP中 spl_autoload_register() 函数用法

    这篇文章主要介绍了PHP中spl_autoload_register()函数用法,结合实例形式分析了__autoload函数及spl_autoload_register函数的相关使用技巧,需要的朋友可 ...

  4. supersocket实现你的命令

    现在, 如果你有一个命令行协议的服务器实例 "IronPythonServer", 而且我们要用 Python 创建一个 "ADD" 命令用于让两个整数相加,然 ...

  5. History和Location

    Location 对象属性属性 描述hash 设置或返回从井号 (#) 开始的 URL(锚).host 设置或返回主机名和当前 URL 的端口号.hostname 设置或返回当前 URL 的主机名.h ...

  6. HDU 2844 混合背包、

    题意:一个人想买手表,给你n个价值的硬币,然后给你n个价值硬币对应的个数.但是呢,这个人只知道这个手表的价格不超过m元.问他最多能买多少种价值的手表 思路:dp背包专题 但是- - 一直不知道该怎么d ...

  7. 教你如何成为Spark大数据高手?

    教你如何成为Spark大数据高手? Spark目前被越来越多的企业使用,和Hadoop一样,Spark也是以作业的形式向集群提交任务,那么如何成为Spark大数据高手?下面就来个深度教程. Spark ...

  8. Vue 2 难点汇总

    数据侦听 Vue.$watch   watch提供了观察和响应实例上数据变动的办法,当有一些数据需要跟随其他数据变化而变化时,如子组件某个数据依赖来自于父组件的prop计算.很直观的会想到计算这功能和 ...

  9. Django OMR QuerySet的特性/存在意义

    QuerySet存在的意义主要在惰性机制和缓存两点 ---------->惰性机制: 所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个Quer ...

  10. HDU 1568

    - - 我自己开始以为是数值范围是1到100000000.... 搞了半天才发现是斐波那契数列的项数1到100000000 坑爹.!! 不会,只能看网上大牛的题解. 具体解释请看:http://www ...