Pinia介绍:
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
Pinia 大小只有 1kb 左右,超轻量级,你甚至可能忘记它的存在!
相比 Vuex,Pinia 的优点:
- 更贴合 Vue 3 的 Composition API 风格,学习成本更低
- 不需要像Vuex中要区分 Mutation 和 Action,Pinia统一使用 Actions 操作状态
- 支持 TypeScript,可以充分利用 TS 的静态类型系统
- 模块化管理 States, 每个模块是一个 Store
- 直观的 Devtools,可以看到每个 State 的变化
安装:
npm install pinia
# 或者
yarn add pinia
案列:
/src/router/index.js 路由器
import { createRouter, createWebHashHistory,createWebHistory } from "vue-router"; //导入vue-router路由模块,createWebHashHistor函数
//import Home from "../views/Home.vue" //异步加载的组件,这里不需要
//import List from "../views/List.vue" //异步加载的组件,这里不需要进行导入,所以要注释掉const routes = [{path: "/", //路径: redirect: {name: "ListA" //重定向到路由名称为mylist的路由中,这样当浏览器输入的是:http://localhost:5173/ 则会重定向跳转到 http://localhost:5173/list}},{path: "/lista", //路径//当路由被触发时,该组件才会被异步加载,举列:打开页面就不会加载所有的组件,而是根据当前页面需要的组件进行异步加载//这样可以减少初始加载时间,提升用户体验,同时也节省了不必要的资源消耗。name:"ListA",component: () => import("../views/ListA.vue")},{path: "/listb", //路径//当路由被触发时,该组件才会被异步加载,举列:打开页面就不会加载所有的组件,而是根据当前页面需要的组件进行异步加载//这样可以减少初始加载时间,提升用户体验,同时也节省了不必要的资源消耗。name:"ListB",component: () => import("../views/ListB.vue")}
]//创建路由对象
const router = createRouter({//history:createWebHashHistory() 这种方式是按照hash路由模式来路由导航,这种路由模式的url地址会存在 /#/ 样式是:http://localhost:5173/#/listhistory: createWebHistory(), //这种方式基于浏览器 history API 的路由模式,url的样式是:http://localhost:5173/listroutes, //routes:routes的缩写})export default router //导出router路由对象//导出router路由对象
Pinia状态管理器:模块
/src/store/useListAStore.js ListA.vue组件单独使用的状态管理器模块
/*js文件的命名建议:use+组件名称+Store 举列:用于ListA组件的store 我的取名就是 useListAStore.js
*/import { defineStore } from 'pinia'
import axios from 'axios'// Option Store风格案列演示:如下//第一个参数是唯一的storeId
//第二个参数是一个对象
const useListAStore = defineStore("ListAStoreId", {// 为了完整类型推理,推荐使用箭头函数state: () => {return {// 所有这些属性都将自动推断出它们的类型name: 'Eduardo',age: 20,email: 'abc@qq.com',datalist: [],}},actions: {getDataList() {const result = async axios({url: "https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=7069698",headers: {'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16992764191480200349024257"}','X-Host': 'mall.film-ticket.film.list'}})this.datalist = result.data.data.films},async changeName(newname) {this.name = newname;}},getters: {filterDataList(state) {return (keyword) => {return state.datalist.filter(item => item.name.includes(keyword));}}},
})export default useListAStore //导出
/src/store/useListBStore.js ListB.vue组件单独使用的状态管理器模块
/*js文件的命名建议:use+组件名称+Store 举列:用于ListA组件的store 我的取名就是 useListAStore.js
*/import { defineStore } from 'pinia'
import axios from 'axios'// Option Store风格案列演示:如下//第一个参数是唯一的storeId,注意别与其它模块的storeId重名(其实这个storeId我们开发人员一般用不到)
//第二个参数是一个对象
const useListBStore = defineStore("ListBStoreId", {// 为了完整类型推理,推荐使用箭头函数state: () => {return {// 所有这些属性都将自动推断出它们的类型name: '张三',datalist: [],}},actions: {async getDataList() {//异步const result = await axios({url: "https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=3777796",headers: {'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16992764191480200349024257","bc":"110100"}','X-Host': 'mall.film-ticket.cinema.list'}});this.datalist = result.data.data.cinemas},async changeName(newname) {this.name = newname;}},getters: {filterDataList(state) {return (type) => { return state.datalist.filter(item => item.eTicketFlag == type)}}},
})export default useListBStore //导出
注册:路由器 和 状态管理器
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'import router from "../src/router/index.js" //导入状态管理器js
//import store from "../src/store/index.js" //导入状态管理器js import { createPinia} from 'pinia' //导入状态管理器js
const pinia=createPinia();var app=createApp(App)
app.use(router);
app.use(pinia); //注册pinia状态管理器 菠萝//app.use(store) //注册vuex插件:状态管理器app.mount("#app")
使用:
ListA.vue组件:电影列表
<template><div><div><!-- 从useListAStore.js模块下的state中取数:获取useListAStore.js模块下state中的name -->姓名: {{ store.name }}</div><input type="text" v-model.lazy="keyword" placeholder="搜索"><ul><!-- 从useListAStore.js模块下的Getters中取数:执行Getters中的filterDataList方法 --><li v-for="item in store.datalist" :key="item.filmId">{{ item.name }}</li></ul></div>
</template>
<script setup>
// VCA中不支持辅助函数,因为辅助函数中是用this.$store,而VCA中没有绑定this的
import { useStore } from 'vuex'
import { ref, onMounted, onBeforeUnmount } from 'vue'
import useListAStore from '../store/useListAStore.js'const store = useListAStore();store.changeName("王五");//$patch的用法:// store.name="张三";
// store.age=30;
// store.email="123@qq.com";
// 上面三条数据的修改,可以用store.$patch方法统一修改:如下:
// store.$patch({
// name:"张三",
// age:30,
// email:"123@qq.ccom"
// })const keyword = ref("");
onMounted(() => {if (store.datalist.length === 0) {store.getDataList(); //执行useListAStore.js模块中Actions中的getDataList方法 }
})onBeforeUnmount(() => {store.$reset() //对useListAStore.js模块下store里面state中的所有数据进行重置:注意是重置
})</script>
<style scoped>
li {padding: 10px;
}
</style>
ListB.vue组件:影院列表
<template><div><!-- 从store中的state中取数:获取useListBStore.js模块state中的name --><div> 姓名:{{ store.name }}</div><select v-model="type"><option :value="0">APP订票</option><option :value="1">前台兑换</option></select><ul><!-- 从store中的Getters中取数:执行useListBStore.js模块Getters中的filterDataList方法 --><li v-for="item in store.filterDataList(type)" :key="item.cinemaId"> {{ item.name }}</li></ul></div>
</template>
<script setup>
// VCA中不支持辅助函数,因为辅助函数中是用this.$store,而VCA中没有绑定this的import { ref, onMounted } from 'vue'
import useListBStore from '../store/useListBStore.js'
const store = useListBStore();const type = ref(0);
onMounted(() => {if (store.datalist.length === 0) {store.getDataList(); //执行useListBStore.js模块中Actions中的getDataList方法}
})
</script>
App.vue根组件
<template><div><div>{{store.name}}</div><ul class="nvabar"><RouterLink custom to="/ListA" v-slot="{ isActive, navigate }"><li @click="navigate"><span :class="isActive ? 'highlighter' : ''">电影列表</span></li></RouterLink><RouterLink custom to="/ListB" v-slot="{ isActive, navigate }"><li @click="navigate"><span :class="isActive ? 'highlighter' : ''">影院列表</span></li></RouterLink></ul><router-view></router-view></div>
</template>
<script setup>
import { ref, } from 'vue';import ListA from "./views/ListA.vue" //导入Home组件:
import ListB from "./views/ListB.vue" //导入List组件:import useListAStore from './store/useListAStore.js'const store=useListAStore();</script>
<style scoped>
.nvabar {/*固定定位:元素的位置相对于浏览器窗口是固定位置。即使窗口是滚动的它也不会移动*//* position: fixed; *//*显示在底部*//* bottom: 0; */display: flex;/* width: 100%; */height: 50px;line-height: 50px;text-align: center;
}.nvabar li {flex: 1;list-style-type: none;
}.highlighter {/* 高亮 */color: red;border-bottom: 3px solid red;padding-bottom: 7px;}
</style>