赞
踩
import { createApp } from 'vue'
import App from './App.vue'
// 1、引入
import {createPinia} from 'pinia';
// 2、创建
const pinia = createPinia();
// 3、挂载
createApp(App).use(pinia).mount('#app');
Test.vue
import { defineStore } from "pinia"; // 1.定义并导出容器 export const useTestStore = defineStore("test", { /* 类似于组件中的data,用来存储全局状态的 1、尽量使用函数,为了在服务器端渲染的时候避免交叉请求导致的数据状态污染。 2、尽量使用箭头函数,为了更好的ts类型推导 */ state: () => { return { count: 10, }; }, /* 类似于组件的computed,用来封装计算属性,有缓存的功能 */ getters: {}, /* 类似于methods,封装业务逻辑,修改state */ actions: {}, });
Test.vue
<template>
<div>{{ testStore.count }}</div>
</template>
<script setup lang="ts">
import { useTestStore } from "../store";
const testStore = useTestStore();
</script>
<style scoped>
</style>
Test.vue
<template> <div> <div>直接获取:{{ testStore.count }}</div> <div>解构获取:{{ count }}</div> </div> </template> <script setup lang="ts"> import { storeToRefs } from "pinia"; import { useTestStore } from "../store"; const testStore = useTestStore(); const { count } = storeToRefs(testStore); console.log(count.value); </script> <style scoped> </style>
Test.vue
<template> <div> <div>直接获取:{{ testStore.count }}</div> <div>解构获取:{{ count }}</div> <button @click="btn">count++</button> </div> </template> <script setup lang="ts"> import { useTestStore } from "../store"; const testStore = useTestStore(); /* pinia内部将数据进行了响应式处理,如果我们直接通过解构赋值的方式来 获取值,那么获取到的值将不是响应式的 */ const { count } = testStore; // 修改pinia仓库中的值 const btn = function () { testStore.count++; }; </script> <style scoped> </style>
store
import { defineStore } from "pinia"; // 1.定义并导出容器 export const useTestStore = defineStore("test", { /* 类似于组件中的data,用来存储全局状态的 1、尽量使用函数,为了在服务器端渲染的时候避免交叉请求导致的数据状态污染。 2、尽量使用箭头函数,为了更好的ts类型推导 */ state: () => { return { count: 10, arr: [1, 2, 3], }; }, /* 类似于组件的computed,用来封装计算属性,有缓存的功能 */ getters: {}, /* 类似于methods,封装业务逻辑,修改state */ actions: { changeState(num: number) { this.count = this.count + num; this.arr.push(this.arr.length + 1); }, }, });
Test.vue
<template> <div> <div>count:{{ testStore.count }}</div> <div>arr:{{ testStore.arr }}</div> <button @click="btn">按钮</button> </div> </template> <script setup lang="ts"> import { useTestStore } from "../store"; const testStore = useTestStore(); const btn = function () { // 修改数据方式1 testStore.count++; // 修改数据方式2 批量修改多个数据 $patch(对象) testStore.$patch({ count: testStore.count + 1, arr: [...testStore.arr, testStore.arr.length + 1], }); // 修改数据方式3 $patch(函数) testStore.$patch((state) => { state.count++; state.arr.push(state.arr.length + 1); }); // 修改数据方式4 调用action,允许传入参数 推荐这种方式,方便集中管理数据操作的行为 testStore.changeState(2); }; </script> <style scoped> </style>
store
...
actions: {
...
test: () => {
console.log(this);
},
},
...
Test.vue
// 测试action中定义了箭头函数
testStore.test();
store
import { defineStore } from "pinia";
console.log(this);
箭头函数的this指向取决于它的父级this。见下方两端代码示例
const fn = function(obj) { obj.clg(); }; // obj定义在全局中,因此this指向是window const obj = { clg: () => { console.log(this); } } const fn2 = function() { fn(obj); }; fn2();
const fn = function(obj) { obj.clg(); }; function main() { return { clg: () => { console.log(this); } } }; const fn2 = function() { // 手动绑定this指向到一个对象 fn(main.call({ name: "xxx" })); }; fn2();
store
...
getters: {
DoubleCount(state) {
// 拥有缓存功能,不会多次调用值,函数执行多次
console.log("DoubleCount被调用了");
return state.count * 2;
},
// 如果在getter中使用this而不使用state,那么需要手动给返回值定义类型
CountAddTen(): number {
return this.count + 10;
},
},
...
Test.vue
// 调用多次
console.log(testStore.DoubleCount);
console.log(testStore.DoubleCount);
console.log(testStore.DoubleCount);
console.log(testStore.DoubleCount);
console.log(testStore.CountAddTen);
store
import { defineStore } from "pinia"; import { queryGoods, IGoods, IShoppingCartItem, queryShoppingCart, addShoppingCart, updateShoppingCart, deleteShoppingCartItem, } from "../api"; // 1.定义并导出容器 export const useStateStore = defineStore("main", { /* 类似于组件中的data,用来存储全局状态的 1、尽量使用函数,为了在服务器端渲染的时候避免交叉请求导致的数据状态污染。 2、尽量使用箭头函数,为了更好的ts类型推导 */ state: () => { return { count1: 10, count2: 20, arr: [1, 2, 3], }; }, /* 类似于组件的computed,用来封装计算属性,有缓存的功能 */ getters: { count1Double(state) { // 拥有缓存功能,不会多次调用值,函数执行多次 console.log("count1Double被调用了", state.count1); return state.count1 * 2; }, // 如果在getter中使用this而不使用state,那么需要手动给返回值定义类型 count2Double(): number { return this.count2 * 2; }, }, /* 类似于methods,封装业务逻辑,修改state */ actions: { changeState(num: number) { this.count1 = this.count1 + num; this.arr.push(this.arr.length + 1); }, test: () => { console.log(this); }, }, }); // 商品仓库 export const useGoodsStore = defineStore("goods", { state: () => { return { goods: [] as IGoods[], }; }, getters: {}, actions: { async queryGoods() { const result = await queryGoods(); this.goods = result.data; }, }, }); // 购物车仓库 export const useShoppingCartStore = defineStore("shoppingCart", { state: () => { return { shoppingCart: [] as IShoppingCartItem[], }; }, getters: { priceSum(state): number { let sum = 0; state.shoppingCart.forEach((item: IShoppingCartItem) => { sum += item.price * item.amount; }); return sum; }, }, actions: { // 查询购物车中的内容 async queryShoppingCart() { const result = await queryShoppingCart(); this.shoppingCart = result.data; }, // 向购物车中添加商品 addShoppingCart: function (good: IGoods) { const result = this.shoppingCart.map((item: IShoppingCartItem) => { if (item.id === good.id) { return item; } return false; }); const isExist = result.find( (item: boolean | IShoppingCartItem) => item !== false ); if (!isExist) { // 发送新增接口 addShoppingCart({ ...good, amount: 1 }).then((response) => { if (response.status === 201) { this.shoppingCart.push({ ...good, amount: 1 }); } }); } else { // 发送修改接口 updateShoppingCart(good, isExist.amount + 1).then((response) => { if (response.status === 200) { this.shoppingCart = this.shoppingCart.map((item) => { if (item.id === good.id) { item.amount++; } return item; }); } }); } }, // 修改购物车中商品的数量 updateShoppingCart: function (cartItem: IShoppingCartItem, amount: number) { updateShoppingCart(cartItem, amount).then((response) => { if (response.status === 200) { this.shoppingCart.forEach((item) => { if (item.id === cartItem.id) item.amount = amount; }); } }); }, // 删除购物车中的某商品 deleteShoppingCartItem: function (cartItem: IShoppingCartItem) { deleteShoppingCartItem(cartItem) .then((response) => { if (response.status === 200) { this.shoppingCart = this.shoppingCart.filter( (item) => item.id !== cartItem.id ); } }) .catch((err) => { console.log(err); }); }, }, });
request.ts请求拦截器
import axios from "axios"; // import config from "../config/request.js"; // create an axios instance const request = axios.create({ // baseURL: import.meta.env['VITE_APP_BASE_API'] as string, // url = base url + request url // withCredentials: true, // send cookies when cross-domain requests timeout: 3000, // request timeout baseURL: "http://localhost:3004", }); // request interceptor request.interceptors.request.use( (c) => { return c; }, (error) => { return Promise.reject(error); } ); // response interceptor request.interceptors.response.use( (response) => { if (response.status === 200) { console.log("请求成功", response.data); } else { console.log("接口失败"); } return response; }, (error) => { return Promise.reject(error); } ); export default request;
api/index.ts
import request from "./request"; export interface IGoods { id: number; name: string; price: number; } export interface IShoppingCartItem extends IGoods { amount: number; } // 查询所有的商品 export const queryGoods = function () { return request({ //请求类型 method: "GET", //URL url: "/goods", }); }; // 查询购物车中的内容 export const queryShoppingCart = function () { return request({ //请求类型 method: "GET", //URL url: "/shoppingCart", }); }; // 向购物车中新增商品 export const addShoppingCart = function (shoppingCartitem: IShoppingCartItem) { return request({ //请求类型 method: "POST", //URL url: "/shoppingCart", data: shoppingCartitem, }); }; // 修改购物车中某商品的数量 export const updateShoppingCart = function ( shoppingCartItem: IShoppingCartItem | IGoods, amount: number ) { return request({ //请求类型 method: "PUT", //URL url: `${"/shoppingCart/" + shoppingCartItem.id}`, data: { ...shoppingCartItem, amount, }, }); }; // 删除购物车中的某商品 export const deleteShoppingCartItem = function ( shoppingCartItem: IShoppingCartItem ) { return request({ //请求类型 method: "DELETE", //URL url: `${"/shoppingCart/" + shoppingCartItem.id}`, }); };
ShoppingCart.vue
<template> <div> <div>商品货架</div> <div v-for="good in goods" :key="good.id"> <div>商品名:{{ good.name }}</div> <div>价格:{{ good.price }}¥</div> <button @click="addToShoppingCart(good)">添加到购物车</button> </div> <br /> <div> <div>我的购物车</div> <div v-for="cartItem in shoppingCart" :key="cartItem.id"> <div>商品名:{{ cartItem.name }}</div> <div> 数量:<button @click="reduceAmount(cartItem)">-</button >{{ cartItem.amount }}<button @click="addAmount(cartItem)">+</button> </div> <div>价格:{{ cartItem.amount * cartItem.price }}¥</div> <button @click="deleteCartItem(cartItem)">删除</button> </div> <div>总价:{{ priceSum }}</div> </div> </div> </template> <script setup lang="ts"> import { useGoodsStore, useShoppingCartStore } from "../store/index"; import { storeToRefs } from "pinia"; import { IGoods, IShoppingCartItem } from "../api"; const goodsStore = useGoodsStore(); const shoppingCartStore = useShoppingCartStore(); // 初始化获取所有商品的数据 goodsStore.queryGoods(); shoppingCartStore.queryShoppingCart(); // 需要使用storeToRefs来实现 const { goods } = storeToRefs(goodsStore); const { shoppingCart, priceSum } = storeToRefs(shoppingCartStore); const addToShoppingCart = function (good: IGoods) { console.log(good); shoppingCartStore.addShoppingCart(good); }; const reduceAmount = function (cartItem: IShoppingCartItem) { shoppingCartStore.updateShoppingCart(cartItem, cartItem.amount - 1); }; const addAmount = function (cartItem: IShoppingCartItem) { shoppingCartStore.updateShoppingCart(cartItem, cartItem.amount + 1); }; const deleteCartItem = function (cartItem: IShoppingCartItem) { shoppingCartStore.deleteShoppingCartItem(cartItem); }; </script> <style scoped> </style>
db.json
{ "goods": [ { "id": 1, "name": "苹果", "price": 10 }, { "id": 2, "name": "橘子", "price": 15 }, { "id": 3, "name": "西瓜", "price": 8 } ], "shoppingCart": [ { "id": 1, "name": "苹果", "price": 10, "amount": 3 }, { "id": 2, "name": "橘子", "price": 15, "amount": 4 }, { "id": 3, "name": "西瓜", "price": 8, "amount": 4 } ] }
启动后端接口json-server
启动项目
git clone https://gitee.com/ctbaobao/csdn-wang-yuanrou.git -b vue3-vite-ts-pinia
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。