Vue.js实现购物车功能


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}}&nbsp;免邮费</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}}&nbsp;免邮费</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>
上次更新: 11/9/2019, 7:22:59 PM