文章目录
搭建环境
- npm init vite@latest 搭建vue-ts环境vite中文文档
- npm i pinia
- 修改
main.ts
文件
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.定义并导出容器exportconst 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.定义并导出容器exportconst 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>
注意不能使用箭头函数定义action
store
...
actions:{...test:()=>{console.log(this);},},...
Test.vue
// 测试action中定义了箭头函数
testStore.test();
store
import{ defineStore }from"pinia";console.log(this);
为什么呢?
箭头函数的this指向取决于它的父级this。见下方两端代码示例
constfn=function(obj){
obj.clg();};// obj定义在全局中,因此this指向是windowconst obj ={clg:()=>{
console.log(this);}}constfn2=function(){fn(obj);};fn2();
constfn=function(obj){
obj.clg();};functionmain(){return{clg:()=>{
console.log(this);}}};constfn2=function(){// 手动绑定this指向到一个对象fn(main.call({name:"xxx"}));};fn2();
getters的使用
store
...
getters:{DoubleCount(state){// 拥有缓存功能,不会多次调用值,函数执行多次console.log("DoubleCount被调用了");return state.count *2;},// 如果在getter中使用this而不使用state,那么需要手动给返回值定义类型CountAddTen():number{returnthis.count +10;},},...
Test.vue
// 调用多次console.log(testStore.DoubleCount);console.log(testStore.DoubleCount);console.log(testStore.DoubleCount);console.log(testStore.DoubleCount);console.log(testStore.CountAddTen);
pinia与Vue devtools
购物车案例
项目目录
项目文件
store
import{ defineStore }from"pinia";import{
queryGoods,
IGoods,
IShoppingCartItem,
queryShoppingCart,
addShoppingCart,
updateShoppingCart,
deleteShoppingCartItem,}from"../api";// 1.定义并导出容器exportconst 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{returnthis.count2 *2;},},/*
类似于methods,封装业务逻辑,修改state
*/
actions:{changeState(num:number){this.count1 =this.count1 + num;this.arr.push(this.arr.length +1);},test:()=>{console.log(this);},},});// 商品仓库exportconst useGoodsStore =defineStore("goods",{state:()=>{return{
goods:[]as IGoods[],};},
getters:{},
actions:{asyncqueryGoods(){const result =awaitqueryGoods();this.goods = result.data;},},});// 购物车仓库exportconst 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:{// 查询购物车中的内容asyncqueryShoppingCart(){const result =awaitqueryShoppingCart();this.shoppingCart = result.data;},// 向购物车中添加商品addShoppingCart:function(good: IGoods){const result =this.shoppingCart.map((item: IShoppingCartItem)=>{if(item.id === good.id){return item;}returnfalse;});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 instanceconst 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)=>{returnPromise.reject(error);});// response interceptor
request.interceptors.response.use((response)=>{if(response.status ===200){console.log("请求成功", response.data);}else{console.log("接口失败");}return response;},(error)=>{returnPromise.reject(error);});exportdefault request;
api/index.ts
import request from"./request";exportinterfaceIGoods{
id:number;
name:string;
price:number;}exportinterfaceIShoppingCartItemextendsIGoods{
amount:number;}// 查询所有的商品exportconstqueryGoods=function(){returnrequest({//请求类型
method:"GET",//URL
url:"/goods",});};// 查询购物车中的内容exportconstqueryShoppingCart=function(){returnrequest({//请求类型
method:"GET",//URL
url:"/shoppingCart",});};// 向购物车中新增商品exportconstaddShoppingCart=function(shoppingCartitem: IShoppingCartItem){returnrequest({//请求类型
method:"POST",//URL
url:"/shoppingCart",
data: shoppingCartitem,});};// 修改购物车中某商品的数量exportconstupdateShoppingCart=function(
shoppingCartItem: IShoppingCartItem | IGoods,
amount:number){returnrequest({//请求类型
method:"PUT",//URL
url:`${"/shoppingCart/"+ shoppingCartItem.id}`,
data:{...shoppingCartItem,
amount,},});};// 删除购物车中的某商品exportconstdeleteShoppingCartItem=function(
shoppingCartItem: IShoppingCartItem
){returnrequest({//请求类型
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
本文转载自: https://blog.csdn.net/weixin_44242181/article/details/125355753
版权归原作者 王元肉 所有, 如有侵权,请联系我们删除。
版权归原作者 王元肉 所有, 如有侵权,请联系我们删除。