通常,我们做移动端商城的时候,通常会有购物车模块,那购物车模块有两种实现方式,一是储存在后台通过接口获取到购物车信息,二是存在用户手机本地,第一种方法只要调用接口获取比较简单,这里介绍的是第二种方法,利用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. Getting started with the basics of programming exercises_2

    1.编写简单power函数 #include<stdio.h> int power(int m, int n); // test power function int main(void) ...

  2. Tyvj 1864 [Poetize I]守卫者的挑战

    P1864 [Poetize I]守卫者的挑战时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻 ...

  3. html5的开发

    1.html5的开发组织者: (1)WHATWG:由Apple.Mozilla.Google.Opera等浏览器开发者组成,成立于2004年.WHATWG开发HTML和Web应用API,同时为各浏览器 ...

  4. HDU 1698 Just a Hook 线段树区间更新、

    来谈谈自己对延迟标记(lazy标记)的理解吧. lazy标记的主要作用是尽可能的降低时间复杂度. 这样说吧. 如果你不用lazy标记,那么你对于一个区间更新的话是要对其所有的子区间都更新一次,但如果用 ...

  5. spring security BCryptPasswordEncoder加密解密,不错的随机盐,不错的加密解密方法

    项目中用这个加密感觉不错啊,推荐: 1.先大体看看,了解一下 浅谈使用springsecurity中的BCryptPasswordEncoder方法对密码进行加密(encode)与密码匹配(match ...

  6. Intellij IDEA 如何使用Jrebel热部署

    My Jrebel 已经不再提供免费使用了,或使用破解版Jrebel 或可以移步至 HotSwapAgent,或使用破解的Jrebel. 一个java web项目,在写的过程中我们需要不断调试,如果没 ...

  7. 用户模式 Linux 移植

    用户模式 Linux (UML) 是一个有趣的概念. 它被构建为一个分开的 Linux 内核移植, 有 它自己的 arch/um 子目录. 它不在一个新的硬件类型上运行, 但是; 相反, 它运行在一 ...

  8. Linux 设备模型

    在 2.5 开发循环中一个声明的目标是为内核创建一个统一的设备模型. 之前的内核没有单一的数据结 构, 使它们可以来获取关于系统如何整合的信息. 尽管缺乏信息, 有时事情也进行的不错. 新系统, 带 ...

  9. jQuery---鼠标滚轮控制div横向滚动条左右移动

    HTML <div class="table-responsive"> <div class="fhtable" style="wi ...

  10. CodeForces - 617E XOR and Favorite Number (莫队+前缀和)

    Bob has a favorite number k and ai of length n. Now he asks you to answer m queries. Each query is g ...