pinia

  • 安装npm i pinia
  • 导入import { createPinia} from 'pinia'
  • 注册 app.use(createPinia())
使用
  • index.ts
/**
 * 注册容器
 */
import { defineStore } from 'pinia'

// 定义容器
// 参数1:容器的 id,必须唯一,可以理解为就是有名字的模块
// 参数2:选项对象
export const useMainStore = defineStore('main', {
  // 类似组件的 data,用来存储全局状态的
  // 注意:
  //   1. 必须是函数,因为容器也要兼容 SSR 服务端渲染,避免多个请求数据交叉污染
  //   2. 必须是箭头函数,这是为了 ts 类型推断
  state: () => {
    return {
      count: 100
    }
  },

  // 类似组件的 computed 计算属性,也有缓存功能
  // 参数1 就是 state 对象
  getters: {

    counter10 (state) {
      return state.count + 10
    }

    // 也可以在 getters 中使用 this,但是这种情况下必须手动标记 getter 的返回值类型
    // counter10 (): number {
    //   return this.count + 10
    // }
  },

  // 类似组件的 methods,主要用来封装操作逻辑
  // 在其中使用 this 操作容器数据,同步异步都支持
  actions: {
    incrementCount (a: string, b: number) {
      // this.count++
      setTimeout(() => {
        this.count++
      }, 1000)
    }
  }
})

  • counter.vue
<template>
  <h2>Counter A</h2>
  <p>{{ mainStore.count }}</p>
  <p>{{ mainStore.counter10 }}</p>
  <p>
    <button @click="handleChangeState">修改 state 数据</button>
  </p>
</template>

<script setup lang="ts">
import { useMainStore } from '../store/index'

// 调用得到容器对象
const mainStore = useMainStore()

const handleChangeState = () => {
  // 方式一:
  // mainStore.count++

  // 方式二:批量更新
  // mainStore.$patch({
  //   count: mainStore.count + 1
  // })

  // 方式三:在 action 中修改
  // Vuex 中调用 mutation 得 commit,调用 action 得 dispatch
  // action 同步异步操作都支持
  mainStore.incrementCount('a', 10)
}
</script>

  • ProductList.vue
<template>
  <ul>
    <li v-for="item in all">
      {{ item.title }} - {{ item.price }}
      <br />
      <button
        :disabled="!item.inventory"
        @click="cartStore.addProductToCart(item)"
      >添加到购物车</button>
    </li>
  </ul>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useProductsStore } from '../store/products'
import { useCartStore } from '../store/cart'

const productsStore = useProductsStore()
const cartStore = useCartStore()

// 异步加载更新数据
productsStore.loadAllProducts()

// 数据解构
// 注意:这种写法是有问题的,不是响应式的,只能拿到一次性的数据
// const { all } = productsStore

// 响应式解构处理,内部其实是被 ref 包裹了
const { all } = storeToRefs(productsStore)

console.log(all.value)
</script>

  • products.ts
/**
 * 注册容器
 */
import { defineStore } from 'pinia'
import { getProducts, IProduct } from '../api/shop'

export const useProductsStore = defineStore('products', {
  state: () => {
    return {
      all: [
        { id: 1, title: 'xxx', price: 10, inventory: 100 }
      ] as IProduct[] // 所以商品列表
    }
  },

  getters: {},

  actions: {
    async loadAllProducts () {
      const ret = await getProducts()
      this.all = ret
    },

    async decrementProduct (product: IProduct) {
      const p = this.all.find(item => item.id === product.id)
      if (p) {
        p.inventory--
      }
    }
  }
})

  • ShoppingCart
<template>
  <div class="cart">
    <h2>你的购物车</h2>
    <p>
      <i>请添加一些商品到购物车.</i>
    </p>
    <ul>
      <li v-for="item in cartStore.cartProducts">{{ item.title }} - {{ item.price }} x {{ item.quantity }}</li>
      <!-- <li>商品名称 - 商品价格 x 商品数量</li>
      <li>商品名称 - 商品价格 x 商品数量</li> -->
    </ul>
    <p>商品总价: {{ cartStore.totalPrice }}</p>
    <p>
      <button @click="cartStore.checkout">结算</button>
    </p>
    <p v-show="cartStore.checkoutStatus">结算{{ cartStore.checkoutStatus }}.</p>
  </div>
</template>

<script setup lang="ts">
import { useCartStore } from '../store/cart'

const cartStore = useCartStore()
</script>

  • shop.ts
export interface IProduct {
  id: number // 唯一标识
  title: string // 名称
  price: number // 价格
  inventory: number // 库存
}

const _products: IProduct[] = [
  { id: 1, title: 'iPad 4 Mini', price: 500.01, inventory: 2 },
  { id: 2, title: 'H&M T-Shirt White', price: 10.99, inventory: 10 },
  { id: 3, title: 'Charli XCX - Sucker CD', price: 19.99, inventory: 5 }
]

/**
 * 获取商品列表
 */
export const getProducts = async () => {
  await wait(100)
  return _products
}

/**
 * 订单结算
 */
export const buyProducts = async () => {
  await wait(100)
  return Math.random() > 0.5
}

async function wait(delay: number) {
  return new Promise((resolve) => setTimeout(resolve, delay))
}

  • cart.ts
import { defineStore } from 'pinia'
import { IProduct, buyProducts } from '../api/shop'
import { useProductsStore } from './products'
// 合并IProduct,但是去除掉inventory
type CartProduct = {
  quantity: number
} & Omit<IProduct, 'inventory'>

export const useCartStore = defineStore('cart', {
  state: () => {
    return {
      cartProducts: [] as CartProduct[],
      checkoutStatus: null as null | string // 结算状态
    }
  },

  getters: {
    totalPrice (state) {
      return state.cartProducts.reduce((price, item) => {
        return price + item.quantity * item.price
      }, 0)
    }
  },

  actions: {
    addProductToCart(product: IProduct) {
      this.checkoutStatus = null
      // this.cartProducts.push(product)
      // 商品是否有库存
      if (product.inventory <= 0) {
        return
      }
      // 购物车中是否已有该商品
      const item = this.cartProducts.find(p => p.id === product.id)
      if (item) {
        //   如果有,则让已有商品的数量 +1
        item.quantity++
      } else {
        //   如果没有,则新增
        this.cartProducts.push({
          id: product.id,
          title: product.title,
          price: product.price,
          quantity: 1 // 刚加到购物车的商品的数量肯定是 1 个
        })
      }
      // 更新商品的库存
      const productsStore = useProductsStore()
      productsStore.decrementProduct(product)
    },

    async checkout () {
      this.checkoutStatus = null // 充值结算状态
      const ret = await buyProducts()
      if (ret) {
        this.checkoutStatus = '成功'
        this.cartProducts = [] // 清除购物车数据
      } else {
        this.checkoutStatus = '失败'
      }
    }
  }
})

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值