Vue基础教程(197)网上购物商城开发实战:别愣着了!代码敲出购物车,你的第一次“云剁手”Vue.js实战攻略

Vue购物车实战入门

深度分析Vue基础教程之网上购物商城开发实战

引言:为啥我们要跟“购物车”过不去?

嘿,屏幕前的你!是不是已经看完了Vue的官方文档,脑子里的v-forv-if已经开始打架了?感觉啥都会了,但一打开代码编辑器,却不知道从何下手?

相信我,你不是一个人!学习任何编程框架,最大的坎儿就是从理论到实践的“惊险一跃”。而“网上购物商城”,简直就是为Vue量身定做的实战练习题!它几乎覆盖了Vue最核心、最基础的所有知识点,而且逻辑清晰,贴近生活,理解起来毫无压力。

今天,咱就不整那些虚头巴脑的概念了。我直接化身你的项目搭档,咱们一起,用Vue的基础语法,从零开始,搭建一个属于我们自己的“剁手乐园”。放心,过程绝对好玩,包教包会,代码可以直接“偷走”那种!

第一章:开工前,咱们得先把“摊位”支棱起来(项目初始化)

想象一下,你要开个网店,总得先有个门面吧?对于Vue项目来说,这个门面就是我们的开发环境。

1.1 创建Vue项目
咱们直接用Vue官方推荐的脚手架工具create-vue,省心又省力。打开你的终端(Terminal),输入以下命令:

npm create vue@latest my-online-shop

然后一路按照提示选择就行(对于初学者,暂时不用选Router和Pinia,我们后面手动加,这样理解更深)。创建完成后,进入项目文件夹,安装依赖,并启动开发服务器:

cd my-online-shop
npm install
npm run dev

看到 http://localhost:5173 上跑起来一个默认页面?恭喜你,你的“数字商铺”地基已经打好了!

1.2 清理与规划
src/componentsApp.vue里默认的内容清一清,咱们要开始画自己的蓝图了。

我们这个迷你商城需要哪些“功能区”呢?

  • 商品展示区(ProductList): 用来摆出我们的商品。
  • 购物车(ShoppingCart): 存放用户想买的宝贝。
  • 导航栏(NavBar): 方便用户在商品区和购物车之间切换。

看,这就是Vue组件化思想的雏形——把一个复杂的页面,拆分成一个个独立、可复用的小部件。

第二章:上货!用v-for把商品“摆”上架

店开好了,不能空着啊!咱们得进货。

2.1 准备商品数据
App.vue里,我们用data选项来当我们的“仓库管理员”,管理所有商品信息。

<!-- App.vue -->
<template>
  <div id="app">
    <NavBar />
    <!-- 主要内容区域,后面会根据路由切换 -->
    <router-view />
  </div>
</template>
<script>
import NavBar from './components/NavBar.vue'

export default {
  name: 'App',
  components: {
    NavBar
  },
  // 这里是我们的“数据仓库”
  data() {
    return {
      products: [
        { id: 1, name: 'Vue信仰咖啡杯', price: 88, image: '/images/cup.jpg', inventory: 10 },
        { id: 2, name: 'React求生手册', price: 66, image: '/images/book.jpg', inventory: 5 },
        { id: 3, name: 'JavaScript防脱发洗发水', price: 128, image: '/images/shampoo.jpg', inventory: 2 },
        { id: 4, name: 'CSS魔法指南', price: 99, image: '/images/css-book.jpg', inventory: 8 },
      ],
      cart: [] // 购物车,一开始是空的
    }
  },
  // 注意:这里我们暂时没有引入Vuex/Pinia,所以用provide来向下传递数据
  provide() {
    return {
      globalData: {
        products: this.products,
        cart: this.cart
      }
    }
  }
}
</script>

2.2 创建商品列表组件
新建src/components/ProductList.vue,是时候展示v-for的真正技术了!

<!-- components/ProductList.vue -->
<template>
  <div class="product-list">
    <h2>欢迎光临,随便看看!</h2>
    <div class="products">
      <!-- v-for 循环渲染每一个商品 -->
      <div v-for="product in products" :key="product.id" class="product-card">
        <img :src="product.image" :alt="product.name" />
        <h3>{{ product.name }}</h3>
        <p class="price">¥{{ product.price }}</p>
        <p class="inventory">库存: {{ product.inventory }}</p>
        <!-- 绑定点击事件,将当前商品传入addToCart方法 -->
        <button @click="addToCart(product)" :disabled="product.inventory === 0">
          {{ product.inventory === 0 ? '售罄' : '加入购物车' }}
        </button>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  inject: ['globalData'], // 接收从App.vue传递下来的全局数据
  computed: {
    products() {
      return this.globalData.products;
    }
  },
  methods: {
    addToCart(product) {
      // 这里就是Vue的响应式魅力所在!
      // 我们直接操作数据,视图会自动更新
      if (product.inventory > 0) {
        // 检查购物车是否已有该商品
        const itemInCart = this.globalData.cart.find(item => item.id === product.id);
        if (itemInCart) {
          itemInCart.quantity++;
        } else {
          this.globalData.cart.push({ ...product, quantity: 1 });
        }
        // 减少库存
        product.inventory--;
        alert(`成功将 ${product.name} 加入购物车!`);
      }
    }
  }
}
</script>
<style scoped>
.products {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.product-card {
  border: 1px solid #ddd;
  padding: 15px;
  border-radius: 8px;
  width: 200px;
  text-align: center;
}
.product-card img {
  width: 100%;
  height: 150px;
  object-fit: cover;
}
.price {
  color: #e44d26;
  font-weight: bold;
  font-size: 1.2em;
}
</style>

深度分析:
看到没?v-for就像是一个“复印机”,根据products数组,一口气复印出N个商品卡片。:key="product.id"是给每个复印件一个独一无二的身份证,让Vue能高效地跟踪每个节点,这可是性能优化的关键点!而@click="addToCart(product)"则完美体现了数据驱动视图的思想:我们不用手动去操作DOM(比如document.createElement),只需要修改cart数组和inventory库存,页面上按钮的状态、库存显示、购物车数量等,全都会自动、神奇地更新!

第三章:核心玩法——购物车与计算属性

购物车可是商城的灵魂,这里面的“算计”可多了。

3.1 创建购物车组件
新建src/components/ShoppingCart.vue

<!-- components/ShoppingCart.vue -->
<template>
  <div class="shopping-cart">
    <h2>你的购物车</h2>
    <div v-if="cart.length === 0">购物车空空如也,快去逛逛吧!</div>
    <div v-else>
      <div v-for="item in cart" :key="item.id" class="cart-item">
        <span>{{ item.name }}</span>
        <span>¥{{ item.price }}</span>
        <div class="quantity-controls">
          <button @click="decreaseQuantity(item)">-</button>
          <span>{{ item.quantity }}</span>
          <button @click="increaseQuantity(item)" :disabled="item.inventory <= 0">+</button>
        </div>
        <span小计:¥{{ item.price * item.quantity }}</span>
        <button @click="removeFromCart(item)" class="remove-btn">删除</button>
      </div>
      <!-- 这里是计算属性的用武之地! -->
      <div class="cart-total">
        <strong>总价:¥{{ cartTotalPrice }}</strong>
      </div>
      <button @click="checkout">一键下单</button>
    </div>
  </div>
</template>
<script>
export default {
  inject: ['globalData'],
  computed: {
    cart() {
      return this.globalData.cart;
    },
    // 计算属性:自动计算总价,依赖变化它会自动重新计算
    cartTotalPrice() {
      return this.cart.reduce((total, item) => total + (item.price * item.quantity), 0);
    }
  },
  methods: {
    increaseQuantity(item) {
      if (item.inventory > 0) {
        item.quantity++;
        // 找到原商品,减少库存
        const originalProduct = this.globalData.products.find(p => p.id === item.id);
        originalProduct.inventory--;
      }
    },
    decreaseQuantity(item) {
      item.quantity--;
      // 找到原商品,增加库存
      const originalProduct = this.globalData.products.find(p => p.id === item.id);
      originalProduct.inventory++;
      // 如果数量减到0,就从购物车移除
      if (item.quantity === 0) {
        this.removeFromCart(item);
      }
    },
    removeFromCart(item) {
      const index = this.cart.indexOf(item);
      if (index > -1) {
        // 归还库存
        const originalProduct = this.globalData.products.find(p => p.id === item.id);
        originalProduct.inventory += item.quantity;
        // 从购物车移除
        this.cart.splice(index, 1);
      }
    },
    checkout() {
      if (this.cart.length > 0) {
        alert(`下单成功!总计:¥${this.cartTotalPrice}。感谢您的光临!`);
        // 清空购物车
        this.cart.length = 0;
      }
    }
  }
}
</script>
<style scoped>
.cart-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  border-bottom: 1px solid #eee;
}
.quantity-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}
.remove-btn {
  background-color: #ff4757;
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer;
}
</style>

深度分析:
computed(计算属性)在这里扮演了“财务总监”的角色。它依赖于cart数组,当cart里的商品数量或单价任何一项发生变化时,cartTotalPrice会自动、高效地重新计算总价。你不需要手动去调用它,Vue的响应式系统会帮你搞定一切。这比在methods里写一个方法然后在模板里调用 getTotalPrice() 要优雅和高效得多,因为它有缓存。

第四章:让页面“动”起来——Vue Router路由配置

一个商城不能只有一个页面啊,我们得让用户能在“商品列表”和“购物车”之间来回切换。

4.1 安装和配置路由
首先,安装Vue Router:

npm install vue-router@4

然后,创建src/router/index.js文件:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import ProductList from '../components/ProductList.vue';
import ShoppingCart from '../components/ShoppingCart.vue';

const routes = [
  { path: '/', component: ProductList },
  { path: '/cart', component: ShoppingCart },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

4.2 修改主入口和导航栏
main.js中引入并使用路由:

// main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router' // 导入路由配置

createApp(App).use(router).mount('#app') // 使用路由

创建导航栏组件src/components/NavBar.vue

<!-- components/NavBar.vue -->
<template>
  <nav class="navbar">
    <h1>我的Vue小店</h1>
    <div class="nav-links">
      <!-- 使用 router-link 组件进行导航 -->
      <router-link to="/">商品列表</router-link>
      <router-link to="/cart">
        购物车
        <!-- 这里可以显示购物车商品总数,又是一个计算属性的好用例! -->
        <span class="cart-count" v-if="cartItemCount > 0">({{ cartItemCount }})</span>
      </router-link>
    </div>
  </nav>
</template>
<script>
export default {
  inject: ['globalData'],
  computed: {
    cartItemCount() {
      // 计算购物车里所有商品的数量总和
      return this.globalData.cart.reduce((count, item) => count + item.quantity, 0);
    }
  }
}
</script>
<style scoped>
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background-color: #f8f9fa;
  border-bottom: 1px solid #dee2e6;
}
.nav-links {
  display: flex;
  gap: 20px;
}
.router-link-active {
  font-weight: bold;
  color: #e44d26;
}
.cart-count {
  background-color: #e44d26;
  color: white;
  border-radius: 50%;
  padding: 2px 6px;
  font-size: 0.8em;
}
</style>

深度分析:
Vue Router让我们的应用变成了单页面应用(SPA)。当你点击<router-link>时,并不会刷新整个页面,而是由Router在背后悄悄地切换<router-view>里的组件。这带来了极其流畅的用户体验。导航栏上那个动态变化的购物车数量({{ cartItemCount }}),再次展现了计算属性和响应式数据的威力。

第五章:总结与升华——你的Vue第一课毕业了

到这里,一个具备核心功能的迷你网上购物商城就完成了!我们来复盘一下,都用到了哪些Vue基础知识:

  1. 响应式数据(dataproductscart是整个应用的心脏,它们一变,视图自动更新。
  2. 模板语法与指令{{ }}插值、v-for列表渲染、v-if条件渲染、v-bind:)属性绑定、v-on@)事件绑定。这是Vue的“肌肉”,负责把数据和DOM连接起来。
  3. 组件化:将UI拆分为独立、可复用的ProductListShoppingCartNavBar组件,让代码结构清晰,易于维护。
  4. 计算属性(computed:用于进行依赖数据的复杂计算,如总价、商品总数,它有缓存,效率高。
  5. 方法(methods:处理用户交互产生的逻辑,如添加商品、增减数量。
  6. Vue Router:管理前端路由,实现多页面切换的体验。

下一步可以做什么?

  • 状态管理: 当应用再复杂一点,provide/inject可能会显得力不从心,这时可以引入Pinia来更科学地管理全局状态。
  • UI库: 自己写CSS太麻烦?可以引入像Element PlusVant这样的UI库,快速搭建美观的界面。
  • 后端连接: 使用Axios从真实的服务器API获取商品数据,而不是写死在代码里。
  • 动画: 用Vue的<Transition>组件给商品加入购物车、页面切换添加丝滑的动画效果。

记住,这个项目虽然小,但它几乎包含了前端MVVM框架最精髓的思想。理解了它,你再去看其他更复杂的Vue项目,或者甚至去学习React、Angular,都会觉得触类旁通。

所以,别光看,赶紧打开你的代码编辑器,亲手敲一遍吧!遇到Bug不要慌,那正是你成长最快的时候。祝你“云剁手”愉快,编程之路越走越顺!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值