当前位置: 首页 > news >正文

六十天前端强化训练之第二十七天之Pinia 状态管理全解与购物车实战案例

=====欢迎来到编程星辰海的博客讲解======

看完可以给一个免费的三连吗,谢谢大佬!

目录

一、Pinia 深度解析

1. Pinia 核心设计

2. 核心概念图解

3. Store 类型对比

Option Store(选项式)

Setup Store(组合式)

4. 响应式原理

二、购物车状态管理实战

1. 项目结构

2. 核心 Store 实现(stores/cart.js)

3. 商品列表组件(ProductList.vue)

4. 购物车组件(ShoppingCart.vue)

三、实现效果说明

四、学习要点总结

五、扩展阅读推荐

官方资源

优质文章

进阶教程


一、Pinia 深度解析

1. Pinia 核心设计

Pinia 是 Vue 官方推荐的新一代状态管理库,具有以下核心优势:

  • TypeScript 原生支持:完整的类型推断和自动补全
  • 模块化架构:天然支持代码分割和按需加载
  • 轻量无冗余:相比 Vuex 减少 40% 的代码量
  • 组合式 API:完美对接 Vue3 的组合式编程范式
  • Devtools 整合:完整的时间旅行调试支持

2. 核心概念图解

3. Store 类型对比

Option Store(选项式)

JAVASCRIPT

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
Setup Store(组合式)

JAVASCRIPT

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const double = computed(() => count.value * 2)
  function increment() {
    count.value++
  }
  return { count, double, increment }
})

4. 响应式原理

Pinia 基于 Vue3 的 reactive() 实现响应式系统:

  • State 自动转换为 reactive 对象
  • Getters 使用 computed 实现计算缓存
  • Actions 作为状态操作方法

二、购物车状态管理实战

1. 项目结构

TEXT

/src
  ├── stores
  │    └── cart.js
  ├── components
  │    ├── ProductList.vue
  │    └── ShoppingCart.vue
  └── App.vue

2. 核心 Store 实现(stores/cart.js)

JAVASCRIPT

import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

export const useCartStore = defineStore('cart', () => {
  // 状态定义
  const items = ref([]) // 购物车商品数组
  const taxRate = 0.1 // 税率(常量)

  // Getter(带参数的派生状态)
  const cartTotal = computed(() => 
    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
  )
  
  const totalWithTax = computed(() => 
    cartTotal.value * (1 + taxRate)
  )

  // Action:添加商品(幂等操作)
  const addToCart = (product, quantity = 1) => {
    const existing = items.value.find(item => item.id === product.id)
    
    if (existing) {
      // 商品存在时增加数量
      existing.quantity += quantity
    } else {
      // 新商品添加购物车
      items.value.push({
        ...product,
        quantity,
        addedAt: new Date().toISOString()
      })
    }
  }

  // Action:移除商品(支持完全移除和减少数量)
  const removeFromCart = (productId, quantity = 1) => {
    const index = items.value.findIndex(item => item.id === productId)
    if (index === -1) return

    if (items.value[index].quantity <= quantity) {
      // 完全移除商品
      items.value.splice(index, 1)
    } else {
      // 减少商品数量
      items.value[index].quantity -= quantity
    }
  }

  // Action:清空购物车
  const clearCart = () => {
    items.value = []
  }

  return {
    items,
    cartTotal,
    totalWithTax,
    addToCart,
    removeFromCart,
    clearCart
  }
})

3. 商品列表组件(ProductList.vue)

VUE

<script setup>
import { useCartStore } from '@/stores/cart'

const cartStore = useCartStore()
const products = [
  { id: 1, name: 'Vue T-Shirt', price: 29.99 },
  { id: 2, name: 'Pinia Mug', price: 15.50 },
  { id: 3, name: 'Vuex Book', price: 39.99 }
]
</script>

<template>
  <div class="product-list">
    <h2>Available Products</h2>
    <div v-for="product in products" :key="product.id" class="product-item">
      <h3>{{ product.name }}</h3>
      <p>Price: \${{ product.price.toFixed(2) }}</p>
      <button @click="cartStore.addToCart(product)">
        Add to Cart
      </button>
    </div>
  </div>
</template>

4. 购物车组件(ShoppingCart.vue)

VUE

<script setup>
import { useCartStore } from '@/stores/cart'
import { storeToRefs } from 'pinia'

const cartStore = useCartStore()
const { items, cartTotal, totalWithTax } = storeToRefs(cartStore)
</script>

<template>
  <div class="shopping-cart">
    <h2>Shopping Cart</h2>
    <div v-if="items.length === 0" class="empty-cart">
      Your cart is empty
    </div>
    <div v-else>
      <div v-for="item in items" :key="item.id" class="cart-item">
        <h3>{{ item.name }}</h3>
        <p>
          Quantity: {{ item.quantity }}
          <button @click="cartStore.removeFromCart(item.id, 1)">-</button>
          <button @click="cartStore.addToCart(item)">+</button>
        </p>
        <p>Price: \${{ (item.price * item.quantity).toFixed(2) }}</p>
        <button @click="cartStore.removeFromCart(item.id, item.quantity)">
          Remove
        </button>
      </div>
      <div class="totals">
        <p>Subtotal: \${{ cartTotal.toFixed(2) }}</p>
        <p>Tax (10%): \${{ (totalWithTax - cartTotal).toFixed(2) }}</p>
        <p class="total">Total: \${{ totalWithTax.toFixed(2) }}</p>
      </div>
      <button @click="cartStore.clearCart" class="clear-btn">
        Clear Cart
      </button>
    </div>
  </div>
</template>

三、实现效果说明


(图示说明:用户添加商品、调整数量、删除商品时,各组件自动同步状态)

  1. 状态共享:多组件同时访问同一购物车状态
  2. 响应式更新:价格计算实时同步
  3. 操作隔离:商品增减逻辑集中管理
  4. 类型安全:完整的TS类型推断

四、学习要点总结

  1. 核心概念

    • Store 作为状态容器
    • State 定义应用状态
    • Getters 实现派生数据
    • Actions 封装业务逻辑
  2. 最佳实践

    JAVASCRIPT

    // 正确的状态解构方式
    const { count } = storeToRefs(store)
    // 错误的方式(破坏响应式)
    const { count } = store
    
  3. 架构原则

    • 单一职责:每个Store聚焦特定领域
    • 低耦合:组件不直接操作其他Store
    • 高内聚:相关逻辑集中管理
  4. 调试技巧

    JAVASCRIPT

    // 浏览器控制台访问
    const store = useCartStore()
    store.$patch({...})
    store.$subscribe((mutation) => {
      console.log('状态变更:', mutation)
    })
    

五、扩展阅读推荐

官方资源

  1. Pinia 官方文档
  2. Vue 状态管理指南
  3. Pinia 与 Vuex 对比指南

优质文章

  1. 深入理解 Pinia 架构设计
  2. 企业级 Pinia 最佳实践
  3. Pinia 插件开发指南
  4. SSR 场景下的 Pinia 使用
  5. Pinia 单元测试全攻略

进阶教程

JAVASCRIPT

// 持久化插件示例
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(createPersistedState({
  auto: true, // 自动持久化所有Store
  storage: sessionStorage
}))

建议运行示例并通过 Vue Devtools 观察状态变更过程,加深理解。义和测试用例。

相关文章:

  • 【Linux】I/O 多路转接:select epoll 技术剖析
  • 安卓 vs iOS 文件系统深度解析:开放自由与封闭安全的终极博弈
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例10,TableView15_10带搜索的导出表格示例
  • [DDD架构]不同数据模型DTO、VO、PO、DAO、DO的含义
  • 自动驾驶系统的车辆动力学建模:自行车模型与汽车模型的对比分析
  • Linux:基础IO---文件描述符
  • JavaSE1.0(实战之图书管理系统)
  • FlowMo: 模式搜索+扩散模型提升图像Token化性能
  • 基于Azure Delta Lake和Databricks的安全数据共享(Delta Sharing)
  • C++异常处理完全指南:从原理到实战
  • 操作系统知识点33
  • 31天Python入门——第10天:深入理解值传递·引用传递以及深浅拷贝问题
  • 计算机网络性能优化相关内容详解
  • Bash语言的测试框架
  • 996引擎-接口测试:音效测试NPC
  • 数据结构—树(java实现)
  • Redis安装与配置:从萌新入门到生产环境搭建
  • UML的使用
  • Java——Random库
  • hackmyvm-Icecream
  • 美“群聊泄密门”始作俑者沃尔兹将离职
  • 李强签署国务院令,公布修订后的《中华人民共和国植物新品种保护条例》
  • 中国固体火箭发动机领域杰出专家赵殿礼逝世,享年92岁
  • 上海:以税务支持鼓励探索更多的创新,助力企业出海
  • 张炜琳已任三明市委常委、宣传部部长
  • “75后”袁达已任国家发改委秘书长