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);
        }
    }
}
相关推荐
学习使我快乐012 分钟前
Express 学习
学习·node.js·express
熠熠仔6 分钟前
《Agentic Design Patterns》概览
学习·设计模式
gCode Teacher 格码致知6 分钟前
Javascript提高:使用canvas绘制一个绚丽的按钮-由Deepseek产生
javascript·css·css3
M ? A19 分钟前
VuReact:Vue转React的增量编译利器
前端·vue.js·后端·react.js·面试·开源·vureact
Tutankaaa22 分钟前
从单场到多场并发:知识竞赛平台的弹性扩展能力
服务器·笔记·学习·职场和发展
小四的小六26 分钟前
WebView安全防护实战:从XSS到中间人攻击,我的踩坑与防御总结
javascript·webview
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_41:(DOMParser 接口详解)
前端·javascript·ui·html·音视频
threelab1 小时前
Three.js 概率统计可视化 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
光影少年1 小时前
useLayoutEffect 和 useEffect 区别、使用场景
开发语言·前端·javascript
奶人五毛拉人一块1 小时前
C++ AVL树的学习
学习·二叉树·avl树·旋转