Vue多文件学习项目综合案例——购物车,黑马vue教程

一、项目截图

二、主要知识点

  • vuex的使用

  • json-server的使用

    shell 复制代码
    json-server --watch index.json

三、需要注意的点

四、Main.js

js 复制代码
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

五、App.vue

html 复制代码
<template>
  <div class="app-container">
    <!-- Header 区域 -->
    <cart-header></cart-header>

    <!-- 商品 Item 项组件 -->
    <cart-item v-for="item in list" :key="item.id" :item="item"></cart-item>

    <!-- Foote 区域 -->
    <cart-footer></cart-footer>
  </div>
</template>

<script>
import CartHeader from '@/components/cart-header.vue'
import CartFooter from '@/components/cart-footer.vue'
import CartItem from '@/components/cart-item.vue'
import {mapState} from "vuex";

export default {
  name: 'App',
  components: {
    CartHeader,
    CartFooter,
    CartItem
  },
  computed:{
    ...mapState('cart',['list'])
  },
  created() {
    this.$store.dispatch('cart/getList')
  }
}
</script>

<style lang="less" scoped>
.app-container {
  padding: 50px 0;
  font-size: 14px;
}
</style>

六、components

cart-footer.vue

html 复制代码
<template>
  <div class="footer-container">
    <!-- 中间的合计 -->
    <div>
      <span>共 {{total}} 件商品,合计:</span>
      <span class="price">¥{{ totalPrice}}</span>
    </div>
    <!-- 右侧结算按钮 -->
    <button class="btn btn-success btn-settle">结算</button>
  </div>
</template>

<script>
import {mapGetters} from 'vuex'

export default {
  name: 'CartFooter',
  computed: {
    ...mapGetters('cart', ['total', 'totalPrice'])
  }
}
</script>

<style lang="less" scoped>
.footer-container {
  background-color: white;
  height: 50px;
  border-top: 1px solid #f8f8f8;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 0 10px;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  z-index: 999;
}

.price {
  color: red;
  font-size: 13px;
  font-weight: bold;
  margin-right: 10px;
}

.btn-settle {
  height: 30px;
  min-width: 80px;
  margin-right: 20px;
  border-radius: 20px;
  background: #42b983;
  border: none;
  color: white;
}
</style>

cart-header.vue

html 复制代码
<template>
  <div class="header-container">购物车案例</div>
</template>

<script>
export default {
  name: 'CartHeader'
}
</script>

<style lang="less" scoped>
.header-container {
  height: 50px;
  line-height: 50px;
  font-size: 16px;
  background-color: #42b983;
  text-align: center;
  color: white;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 999;
}
</style>

cart-item.vue

html 复制代码
<template>
  <div class="goods-container">
    <!-- 左侧图片区域 -->
    <div class="left">
      <img :src="item.thumb" class="avatar" alt="">
    </div>
    <!-- 右侧商品区域 -->
    <div class="right">
      <!-- 标题 -->
      <div class="title">{{ item.name }}</div>
      <div class="info">
        <!-- 单价 -->
        <span class="price">{{ item.price }}</span>
        <div class="btns">
          <!-- 按钮区域 -->
          <button class="btn btn-light" @click="btnClick(-1)">-</button>
          <span class="count">{{ item.count }}</span>
          <button class="btn btn-light" @click="btnClick(1)">+</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CartItem',
  props: {
    item: {
      type: Object,
      request: true
    }
  },
  methods: {
    btnClick(step) {
      const newCount = this.item.count + step;
      const id = this.item.id;
      if (newCount < 1) return;
      this.$store.dispatch('cart/updateCountAsync', {
        id,
        newCount
      })
    }
  }
}
</script>

<style lang="less" scoped>
.goods-container {
  display: flex;
  padding: 10px;

  + .goods-container {
    border-top: 1px solid #f8f8f8;
  }

  .left {
    .avatar {
      width: 100px;
      height: 100px;
    }

    margin-right: 10px;
  }

  .right {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    flex: 1;

    .title {
      font-weight: bold;
    }

    .info {
      display: flex;
      justify-content: space-between;
      align-items: center;

      .price {
        color: red;
        font-weight: bold;
      }

      .btns {
        .count {
          display: inline-block;
          width: 30px;
          text-align: center;
        }
      }
    }
  }
}

.custom-control-label::before,
.custom-control-label::after {
  top: 3.6rem;
}
</style>

七、store

index.js

js 复制代码
import Vue from 'vue'
import Vuex from 'vuex'
import cart from "./modules/cart";

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    cart
  }
})

modules/cart.js

js 复制代码
import axios from "axios";

export default {
    namespaced: true,
    state() {
        return {
            //购物车数据
            list: []
        }
    },
    mutations: {
        updateList(state, newList) {
            state.list = newList
        }
    },
    actions: {
        async getList(context) {
            const res = await axios.get("http://localhost:3000/cart")
            context.commit('updateList', res.data)
        },
        async updateCountAsync(context, obj) {
            await axios.patch(`http://localhost:3000/cart/${obj.id}`, {
                count: obj.newCount
            })
            //当前的this指向$store
            this.dispatch('cart/getList')
        }
    },
    getters: {
        //商品总数
        total(state) {
            return state.list.reduce((sum, item) => sum + item.count, 0);
        },
        //商品总价
        totalPrice(state) {
            return state.list.reduce((sum, item) => sum + item.count * item.price, 0);
        }
    }
}
相关推荐
究极无敌暴龙战神X10 分钟前
前端学习之ES6+
开发语言·javascript·ecmascript
明辉光焱13 分钟前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
Komorebi.py19 分钟前
【Linux】-学习笔记03
linux·笔记·学习
nameofworld43 分钟前
前端面试笔试(二)
前端·javascript·面试·学习方法·数组去重
程序员劝退师_1 小时前
Kafka学习笔记
笔记·学习·kafka
帅比九日1 小时前
【HarmonyOS NEXT】实战——登录页面
前端·学习·华为·harmonyos
李笠^_^1 小时前
Python学习------第八天
学习
Lotay_天天1 小时前
删库跑路,启动!
学习
爱吃生蚝的于勒1 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
hummhumm1 小时前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang