0


学习pinia并搭配json-server,axios,typescript实现一个购物车

文章目录

搭建环境

  1. npm init vite@latest 搭建vue-ts环境vite中文文档
  2. npm i pinia
  3. 修改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
标签: vue.js typescript pinia

本文转载自: https://blog.csdn.net/weixin_44242181/article/details/125355753
版权归原作者 王元肉 所有, 如有侵权,请联系我们删除。

“学习pinia并搭配json-server,axios,typescript实现一个购物车”的评论:

还没有评论