Pinia学习:Vue的存储库

学习之前

最近学校布置了JavaWeb大作业,我决定设计一个购物商城系统。由于之前看过黑马的JavaWeb课程,所以浅浅浅的接触了Vue和ElementUI,觉得用ElementUI来写前端界面可太方便了。但学艺不精必然带来恶果。。。我越写越发现有许多需要专业系统学习Vue才能解决的问题。目前,最困扰着我的问题:Vue的不同组件之间可否共享数据?购物车里的商品能否在不同页面保持一致?为了解决这个问题,我发现了Pinia。希望通过学习Pinia能够解决我的购物商城各个页面共享同一购物车的问题

Pinia简介

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。 如果您熟悉 Composition API,您可能会认为您已经可以通过简单的 export const state = reactive({}) 共享全局状态。

Pinia快速入门

vite工程中引入Pinia:

运行终端中输入:

npm install pinia

安装成功后,创建一个 pinia 实例(根存储)并将其作为插件传递给应用程序:

import { createApp } from 'vue'
// 导入createPinia方法
import { createPinia } from 'pinia'
import App from './App.vue'
// 执行方法得到实例
const pinia = createPinia()
const app = createApp(App)
// 把pinia实例加入到app应用中
app.use(pinia)
app.mount('#app')

一个Pinia快速上手案例 

1. 定义Store

src文件夹下新建store文件夹,随后在src/store中新建js文件counter.js。

// 导入一个方法 defineStore
import { defineStore } from "pinia";
import { ref } from 'vue'
export const useCounterStore =  defineStore('counter', () =>{
    // 定义数据state
    const count = ref(0);
    // 定义修改数据的方法 (action 同步+异步)
    // 同步方法
    const increament = () =>{
        count.value++;
    }
    // 以对象的方式return供组件使用
    return{
        count,
        increament
    }
})

 2. 组件中使用

<script setup>
...
// 1. 导入use打头的方法
import { useCounterStore} from './store/counter.js';
// 2. 执行方法得到store实例对象
const counterStore = useCounterStore();
...
</script>

随后便可以在组件中以counterStore.属性名的形式调用count属性和increament()方法。

示例:

    <button @click="counterStore.increament">{{ counterStore.count }}</button>

点击前: 点击n次后:

小案例便结束啦!

Pinia初步实践

好了,接下来要进行第一个实践了。购物商城系统中的商品信息如何在多个组件间共享?来创建一个goodStore来试试吧!

1. 定义Store

在store文件夹下新建good.js

// 导入一个方法 defineStore
import { defineStore } from "pinia";
import { ref,reactive } from 'vue'

export const useGoodStore =  defineStore('good', () =>{
    // 定义数据state
    const goods = reactive([
        {
            code: 1, // 商品编号
            goodImage: '@/assets/goods/goods1.webp', // 商品图片的存放路径
            goodName: 'Mate60Pro+', // 商品名称
            goodFeatures: ['超聚光主摄', '超可靠玄武架构'], // 商品特性
            goodPrice: 8999 // 商品售价
        },
        {
            code: 2,
            goodImage: '@/assets/goods/goods2.webp',
            goodName: 'Pocket2',
            goodFeatures: ['超平整超可靠', '全焦段XMAGE四摄'],
            goodPrice: 7499
        },
        {
            code: 3,
            goodImage: '@/assets/goods/goods3.webp',
            goodName: 'MatePad Pro 13.2',
            goodFeatures: ['13.2英寸OLED大屏'],
            goodPrice: 5699
        },
        {
            code: 4,
            goodImage: '@/assets/goods/goods4.webp',
            goodName: 'WATCH GT 4',
            goodFeatures: ['科学运动减脂', '专业运动指导', '强劲续航'],
            goodPrice: 1399
        },
    ],);
    // 以对象的方式return供组件使用
    return{
        goods
    }
})

由于能力不足,先把这些数据写死在文件里啦,后面再写成和后端交互的/doge 

2. 组件中使用

<script setup>
...
// 导入方法
import { useGoodStore } from '@/store/good.js';

// 得到商品商店实例
const goodStore = useGoodStore();
...

</script>

接着就可以在组件中使用商品信息啦!

Pinia的getters实现

什么是getters?

getters是Pinia其中的一个核心模块,具有与Vue中的计算属性(computed)相似的功能。具体来说,getters是一个对象,其中包含了一系列的方法。这些方法可以根据state中的状态值进行计算和转换,然后返回一个新的结果。与Vue中的computed属性一样,getters的结果也是被缓存的,只有当其依赖的state值发生变化时,才会重新计算。

如何实现?

Pinia中的getters直接使用computed函数进行模拟:

import { defineStore } from "pinia";
import { ref,computed } from 'vue'
export const useCounterStore =  defineStore('counter', () =>{
    // 定义数据state
    const count = ref(0);
    // 定义修改数据的方法 (action 同步+异步)
    ...
    // getter定义
    const doubleCount = computed(()=> count.value * 2);

    // 以对象的方式return供组件使用
    return{
        count,
        doubleCount,
        ...
    }
})

引入组件后便可以直接调用

<script setup>
import { useCounterStore } from './store/counter.js';
const counterStore = useCounterStore();
</script>
<button @click="counterStore.increament" > {{ counterStore.doubleCount }}</button>

点击前: ,点击一次后:

异步Action实现

// 导入一个方法 defineStore
import { defineStore } from "pinia";
import { ref,computed, reactive } from 'vue'
import axios from 'axios';

export const useCounterStore =  defineStore('counter', () =>{
    ...
    // 定义异步action
    const list = ref([])
    const getList = async () =>{
        // 黑马给的一个地址
        const res = await axios.get('http://geek.itheima.net/v1_0/channels')
        // 把获取到的列表赋值给列表state
        list.value = res.data.data.channels
    }
    // 以对象的方式return供组件使用
    return{
        ...
        list,
        getList
        ...
    }
})
<script setup>

import { useCounterStore } from './store/counter.js';
import { onMounted } from 'vue';

const counterStore = useCounterStore();
onMounted(() => {
    counterStore.getList();
    console.log(counterStore.list);
})

</script>

<template>
    <ul>
        <li v-for="item in counterStore.list" :key="item.id">{{ item.name }}</li>
    </ul>
</template>

显示效果如下:

storeToRefs 

使用storeToRefs函数可以辅助保持数据(state+getter)的响应式结构

<script setup>
import { useCounterStore } from './store/counter.js';
// 导入storeToRefs方法(只负责数据的处理)
import { storeToRefs } from 'pinia';
const counterStore = useCounterStore();
// 直接赋值:响应式丢失
// const {count,doubleCount} = counterStore;
// 方法包裹,保持响应式更新
const { count,doubleCount } = storeToRefs(counterStore);
// store中的action方法不用方法包裹,直接用counterStore结构赋值
const { increament } = counterStore;
</script>

以上就是黑马讲的所有Pinia内容啦!进入实际运用吧! 

购物车实现

购物车需要记录用户添加的商品及不同商品的数量,随后能在界面中渲染显示用户添加了多少商品。

为了实现全局共享的一个购物车,我们先创建一个shopList.js

// 导入一个方法 defineStore
import { defineStore } from "pinia";
import { ref } from 'vue'

export const useShopListStore =  defineStore('shopList', () =>{
    // 定义数据state

    // 用于存放用户购物商品列表
    const shopList = ref([])
    // 用于判断购物车中是否有商品的函数
    const isEmpty = () => {
        return shopList.value.length === 0;
    }
    // 用户添加商品的函数
    const addGood = (good = {},number) =>{
        // 检查购物车重是否有该商品
        for(let i = 0; i < shopList.value.length; i++){
            const j = shopList.value[i];
            if(j.item.code==good.code){
                j.num += number;
                return;
            }
        }
        // 没有重复商品,添加新的商品
        const theGood = {
            item: good,
            num: number
        }
        shopList.value.push(theGood)
    }
    // 获得用户添加商品数量的函数
    const getGoodsNum = () =>{
        let goodNum = 0;
        shopList.value.forEach(e => {
            goodNum += e.num
        })
        return goodNum
    }
    // 以对象的方式return供组件使用
    return{
        shopList,
        isEmpty,
        addGood,
        getGoodsNum
    }
})

购物车Store中定义了一个列表,用于存放用户加入购物车的商品对象,列表中对存储的商品对象进行再次封装,item为商品对象,num为商品对象的数量。

isEmpty()函数用于判断购物车是否为空,用于判断引导栏界面是否要渲染购物车商品数量

当购物车无商品:isEmpty() = true,不渲染

当购物车有商品:isEmpty() = flase,渲染购物车中商品数量

商品数量使用getGoodsNum()获得

addGood()函数传入一个商品对象和商品数量,绑定于“加入购物车”的按钮

<el-button type="danger" size="large" style="width: 200px;
font-weight: 400; font-size: 20px;" 
@click="shopListStore.addGood(good,goodNum)">
    加入购物车
</el-button>

随后每个商品都可以加入购物车啦

成功使用Pinia解决了解决购物商城各个页面共享同一购物车的问题!

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PiniaVue的官方状态管理,用于在Vue3项目中实现数据共享。下面是使用Pinia的基本步骤: 1. 安装Pinia:在Vue3项目中,使用npm或yarn安装Pinia。 2. 创建Pinia实例:在项目的入口文件中,创建一个Pinia实例并将其导出。 3. 定义状态:在需要共享状态的组件中,使用`defineStore`函数定义一个状态存储对象。 4. 注册状态:在组件中使用`useStore`函数注册状态,并在模板中使用。 5. 使用状态:在组件中可以通过`$store`访问状态,并在模板中使用。 下面是一个使用Pinia的示例代码: ```javascript // main.js import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) const pinia = createPinia() app.use(pinia) app.mount('#app') // store.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ }, decrement() { this.count-- } } }) // Counter.vue <template> <div> <p>Count: {{ $store.counter.count }}</p> <button @click="$store.counter.increment()">Increment</button> <button @click="$store.counter.decrement()">Decrement</button> </div> </template> <script> import { useCounterStore } from './store' export default { setup() { const counterStore = useCounterStore() return { counterStore } } } </script> ``` 在上面的示例中,我们首先在`main.js`中创建了一个Pinia实例,并将其应用于Vue应用。然后,在`store.js`中定义了一个名为`counter`的状态存储对象,其中包含一个名为`count`的状态和两个操作。最后,在`Counter.vue`组件中使用`useCounterStore`函数注册状态,并在模板中使用`$store.counter.count`访问状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值