Vue.js实现购物车功能
dobeco 2019-11-6
Vue.js
# 页面搭建——头部和底部布局
# 初始化项目
vue create shop
cd shop
yarn serve
创建Cart组件
cd components
touch Cart.vue
在App.vue中引入Cart组件
<template>
<div id="app">
<cart></cart>
</div>
</template>
<script>
import Cart from './components/Cart.vue'
export default {
name: 'app',
components: {
Cart
}
}
</script>
<style>
*{
padding: 0;
margin: 0;
}
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
}
</style>
# 头部和底部布局
// components/Cart.vue
<template>
<div>
<header>vue购物车</header>
<div class="container"></div>
<footer>
<div class="footer-left">
实际付款:<span>¥999.9免邮费</span>
</div>
<div class="footer-right">立即付款</div>
</footer>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
header {
height: 50px;
line-height: 50px;
text-align:center;
display:fixed;
left:0;
top:0;
z-index: 100;
background-color:white;
border-bottom: 1px solid #ccc;
}
.container {
}
footer {
height: 50px;
width: 100%;
line-height: 50px;
position: fixed;
bottom: 0;
left: 0;
z-index: 100;
border-top: 1px solid #ccc;
display: flex;
justify-content: space-between;
}
.footer-left{
flex: 1;
text-align: right;
font-size: 16px;
padding-right: 6px;
}
.footer-left span {
color: red;
}
.footer-right {
width: 150px;
height: 50px;
line-height: 50px;
text-align:center;
background: red;
color: #fff;
}
</style>
# 商品区块布局
<template>
<div>
<header>vue购物车</header>
<div class="container">
<div class="item">
<div class="logo">
<img src="https://fakeimg.pl/20x20/">
<span>商家名称1</span>
</div>
<div class="details">
<img src="https://fakeimg.pl/90x90/">
<div class="details-list">
<span>夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女</span>
<div class="list-more">
<span>颜色分类:墨绿色</span>
<span>尺码:L-105-115</span>
</div>
<div class="list-price">
¥29.9/件
</div>
</div>
</div>
<div class="num">
<span>购买数量</span>
<div>
<button>-</button>
<input type="text" value="1" />
<button>+</button>
</div>
</div>
</div>
</div>
<footer>
<div class="footer-left">
实际付款:
<span>¥{{totalPrice}} 免邮费</span>
</div>
<div class="footer-right">立即付款</div>
</footer>
</div>
</template>
<script>
export default {
data() {
totalPrice: 0
}
}
</script>
<style scoped>
header {
height: 50px;
width: 100%;
line-height: 50px;
text-align: center;
position: fixed;
left: 0;
top: 0;
z-index: 100;
background-color: white;
border-bottom: 1px solid #ccc;
}
.container {
padding: 50px 0;
background: #fff;
}
.container> .item + .item {
border-top: 1px solid #ccc;
}
.item {
padding: 10px;
}
.logo {
height: 40px;
display: flex;
align-items: center;
}
.logo img {
width: 20px;
height: 20px;
}
.logo span {
color: #888;
font-size: 12px;
margin-left: 20px;
}
.details {
background: #f5f5f5;
padding: 15px;
display: flex;
font-size: 12px;
}
.detial img {
width: 90px;
height: 90px;
}
.details-list{
margin-left: 15px;
color: #888;
}
.list-more span {
display: block;
color: #ccc;
}
.list-price {
font-size: 14px;
}
.num {
color: #888;
padding: 10px;
display: flex;
justify-content: space-between;
}
.num button {
width: 31px;
height: 25px;
background: #e0e0ee;
color: #58595b;
border: none;
outline:none;
}
.num input {
width: 37px;
height: 25px;
border: none;
text-align: center;
background: #fff;
}
footer {
height: 50px;
width: 100%;
line-height: 50px;
position: fixed;
bottom: 0;
left: 0;
z-index: 100;
border-top: 1px solid #ccc;
display: flex;
justify-content: space-between;
}
.footer-left {
flex: 1;
text-align: right;
font-size: 16px;
padding-right: 6px;
}
.footer-left span {
color: red;
}
.footer-right {
width: 150px;
height: 50px;
line-height: 50px;
text-align: center;
background: red;
color: #fff;
}
</style>
# 渲染商品列表
<div class="item" v-for="item in shopCar" :key="item.id">
<div class="logo">
<img :src="item.businessLogo">
<span>{{item.businessName}}</span>
</div>
<div class="details" >
<img :src="item.commodityImg">
<div class="details-list">
<span>{{item.commodityName}}</span>
<div class="list-more">
<span>颜色分类:{{item.commodityColor}}</span>
<span>尺码:{{item.commoditySize}}</span>
</div>
<div class="list-price">
¥{{item.commodityPrice}}/件
</div>
</div>
</div>
<div class="num">
<span>购买数量</span>
<div>
<button>-</button>
<input type="text" value="1" />
<button>+</button>
</div>
</div>
</div>
<script>
export default {
data() {
return {
totalPrice: 0,
shopCar: [
{
id: '001',
businessName: '商品名称1',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '墨绿色',
commoditySize: 'L-105-115',
commodityPrice: '29.9',
},
{
id: '002',
businessName: '商品名称2',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
},
{
id: '003',
businessName: '商品名称3',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
},
{
id: '004',
businessName: '商品名称4',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
},
]
}
},
}
</script>
# 商品总额计算和加减功能
给button绑定点击事件
<div class="num">
<span>购买数量</span>
<div>
<button @click="btn(false,index)">-</button>
<input type="text" :value="item.count" />
<button @click="btn(true,index)">+</button>
</div>
</div>
根据布尔值判断是加还是减
<script>
export default {
data() {
return {
totalPrice: 0,
shopCar: [
{
id: '001',
businessName: '商品名称1',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '墨绿色',
commoditySize: 'L-105-115',
commodityPrice: '29.9',
count: 1
},
{
id: '002',
businessName: '商品名称2',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
count: 1
},
{
id: '003',
businessName: '商品名称3',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
count: 1
},
{
id: '004',
businessName: '商品名称4',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '118',
count: 1
},
]
}
},
mounted(){
this.getTotalPrice();
},
methods: {
getTotalPrice() {
let price = 0;
this.shopCar.forEach( (item)=> {
price += item.count * item.commodityPrice
})
this.totalPrice = price.toFixed(2);
},
btn(bool,index) {
console.log(bool, index);
let shopIndex = this.shopCar[index];
if(bool) {
shopIndex.count++;
this.getTotalPrice()
} else {
if(shopIndex.count<=1) {
return;
}
shopIndex.count--;
this.getTotalPrice();
}
}
}
}
</script>
# 实现右滑删除商品功能
引入mait-ui
安装
yarn add main-ui
在main.js引入
// main.js
import Vue from 'vue'
import App from './App.vue'
import MintUI from 'mint-ui'
import 'mint-ui/lib/style.css'
Vue.use(MintUI)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
完整代码
// Cart.vue
<template>
<div>
<header>vue购物车</header>
<div class="container">
<template v-if="shopCar.length">
<div class="item" v-for="(item,index) in shopCar" :key="item.id">
<mt-cell-swipe
:right="[
{
content: '删除',
style: { background: 'red', color: '#fff',lineHeight:'222px' },
handler: () => del(index)
}
]"
>
<div>
<div class="logo">
<img :src="item.businessLogo" />
<span>{{item.businessName}}</span>
</div>
<div class="details">
<img :src="item.commodityImg" />
<div class="details-list">
<span>{{item.commodityName}}</span>
<div class="list-more">
<span>颜色分类:{{item.commodityColor}}</span>
<span>尺码:{{item.commoditySize}}</span>
</div>
<div class="list-price">¥{{item.commodityPrice}}/件</div>
</div>
</div>
<div class="num">
<span>购买数量</span>
<div>
<button @click="btn(false,index)">-</button>
<input type="text" :value="item.count" />
<button @click="btn(true,index)">+</button>
</div>
</div>
</div>
</mt-cell-swipe>
</div>
</template>
<div v-else style="text-align:center; line-height:50px;" >购物车空空如也</div>
</div>
<footer>
<div class="footer-left">
实际付款:
<span>¥{{totalPrice}} 免邮费</span>
</div>
<div class="footer-right">立即付款</div>
</footer>
</div>
</template>
<script>
export default {
data() {
return {
totalPrice: 0,
shopCar: [
{
id: '001',
businessName: '商品名称1',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '墨绿色',
commoditySize: 'L-105-115',
commodityPrice: '29.9',
count: 1
},
{
id: '002',
businessName: '商品名称2',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
count: 1
},
{
id: '003',
businessName: '商品名称3',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '89',
count: 1
},
{
id: '004',
businessName: '商品名称4',
businessLogo: 'https://fakeimg.pl/20x20/',
commodityImg: 'https://fakeimg.pl/90x90/',
commodityName: '夏季短袖T桖女妈妈宽松大码2019新款蝙蝠袖上衣韩版条纹T桖女',
commodityColor: '酒红色',
commoditySize: 'L-105-115',
commodityPrice: '118',
count: 1
},
]
}
},
mounted() {
this.getTotalPrice();
},
methods: {
getTotalPrice() {
let price = 0;
this.shopCar.forEach((item) => {
price += item.count * item.commodityPrice
})
this.totalPrice = price.toFixed(2);
},
btn(bool, index) {
console.log(bool, index);
let shopIndex = this.shopCar[index];
if (bool) {
shopIndex.count++;
this.getTotalPrice()
} else {
if (shopIndex.count <= 1) {
return;
}
shopIndex.count--;
this.getTotalPrice();
}
},
del(index) {
this.shopCar.splice(index,1);
this.getTotalPrice();
}
}
}
</script>
<style scoped>
header {
height: 50px;
width: 100%;
line-height: 50px;
text-align: center;
position: fixed;
left: 0;
top: 0;
z-index: 100;
background-color: white;
border-bottom: 1px solid #ccc;
}
.container {
padding: 50px 0;
background: #fff;
height: 100%;
}
.container > .item + .item {
border-top: 1px solid #ccc;
}
.item {
/* padding: 10px; */
}
.logo {
height: 40px;
display: flex;
align-items: center;
}
.logo img {
width: 20px;
height: 20px;
}
.logo span {
color: #888;
font-size: 12px;
margin-left: 20px;
}
.details {
background: #f5f5f5;
padding: 15px;
display: flex;
font-size: 12px;
}
.detial img {
width: 90px;
height: 90px;
}
.details-list {
margin-left: 15px;
color: #888;
}
.list-more span {
display: block;
color: #ccc;
}
.list-price {
font-size: 14px;
}
.num {
color: #888;
padding: 10px;
display: flex;
justify-content: space-between;
}
.num button {
width: 31px;
height: 25px;
background: #e0e0ee;
color: #58595b;
border: none;
outline: none;
}
.num input {
width: 37px;
height: 25px;
border: none;
text-align: center;
background: #fff;
}
footer {
height: 50px;
width: 100%;
line-height: 50px;
position: fixed;
bottom: 0;
left: 0;
z-index: 100;
border-top: 1px solid #ccc;
background: #fff;
display: flex;
justify-content: space-between;
}
.footer-left {
flex: 1;
text-align: right;
font-size: 16px;
padding-right: 6px;
}
.footer-left span {
color: red;
}
.footer-right {
width: 150px;
height: 50px;
line-height: 50px;
text-align: center;
background: red;
color: #fff;
}
.item .mint-cell-swipe-button {
line-height: 222px !important;
}
</style>