当前位置: 首页 > ds >正文

后台管理系统-4-vue3之pinia实现导航栏按钮控制左侧菜单栏的伸缩

文章目录

  • 1 引入pinia
    • 1.1 引入并注册(main.js)
    • 1.2 stores/index.js(pinia示例)
      • 1.2.1 定义一个store
      • 1.2.2 组件中使用这个store
  • 2 pinia实现菜单收缩功能
    • 2.1 stores/index.js(pinia)
    • 2.2 侧边栏(CommonAside.vue)
    • 2.3 导航栏(CommonHeader.vue)
  • 3 状态变更的集中管理
    • 3.1 stores/index.js(pinia)
    • 3.2 导航栏(CommonHeader.vue)
  • 4 附录
    • 4.1 computed
    • 4.2 参考附录

使用pinia进行集中式状态管理,定义一个isCollapse,通过导航栏的按钮修改其值,菜单栏随着其值的变化而展开或伸缩。

1 引入pinia

Pinia是一个专门为Vue.js应用程序设计的状态管理库。
它由Vue.js团队成员开发,作为Vuex的继任者,旨在提供更简洁、更直观的API,并更好地支持TypeScript和组合式API。
作用:用于多个组件共享数据。
安装npm install pinia。

1.1 引入并注册(main.js)

在这里插入图片描述

import { createApp } from 'vue'
import App from './App.vue'
import '@/assets/less/index.less';
import router from './router';import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';const app = createApp(App);import { createPinia } from 'pinia';
const pinia = createPinia();
app.use(pinia);for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component);
}app.use(router);
app.use(ElementPlus);
app.mount('#app');

1.2 stores/index.js(pinia示例)

import { defineStore } from "pinia";
import { ref, computed } from "vue";
function initState(){  }
export const useAllDataStore = defineStore("allData", ()=>{//   ref() 相当于state属性//   computed() 相当于getters//   function() 相当于actionsconst state = ref(initState());return {state}
});

响应式: 使用ref()包装state确保它是响应式的。

1.2.1 定义一个store

在这里插入图片描述

1.2.2 组件中使用这个store

在这里插入图片描述

2 pinia实现菜单收缩功能

(1)收缩
在这里插入图片描述
(2)展开
在这里插入图片描述

2.1 stores/index.js(pinia)

定义一个变量isCollapse,初始化为true,用于传递给菜单的collapse属性,控制菜单的折叠。

import { defineStore } from "pinia";
import { ref, computed } from "vue";
function initState(){return {isCollapse:true,}
}
export const useAllDataStore = defineStore("allData", ()=>{//   ref() 相当于state属性//   computed() 相当于getters//   function() 相当于actionsconst state = ref(initState());return {state}
});

注意:useAllDataStore不是默认导出,所以在其他组件中导入时,需要使用{}

2.2 侧边栏(CommonAside.vue)

(1)菜单的宽度需要变化。
(2)el-menu的折叠属性collapse需要随着isCollapse变化。
(3)collapse-transition,是否开启折叠动画,设置为不开启。
(4)h3显示的字样,使用v-show属性,随着isCollapse变化。
在这里插入图片描述

(5)使用计算属性获取值,保持其响应性
computed会“追踪”store.state.isCollapse的变化。
一旦store.state.isCollapse改变,isCollapse.value会自动更新。
在模板中使用时,会自动重新渲染。
(6)为了让width本身也成为响应式数据,能自动更新,也用computed进行包装。
在这里插入图片描述
通过计算属性isCollapse监听store中的isCollapse状态。
通过计算属性width根据折叠状态动态返回宽度值:折叠时64px,展开时180px。

<template><el-aside :width="width"><el-menu background-color="#545c64" :collapse="isCollapse" :collapse-transition="false"><h3 v-show="!isCollapse">后台管理系统</h3><h3 v-show="isCollapse">后台</h3><el-menu-item v-for="item in noChildren" :index="item.path" :key="item.path"><component class="icons" :is="item.icon"></component><span>{{ item.label }}</span></el-menu-item><el-sub-menu v-for="item in hasChildren" :index="item.path" :key="item.path"><template #title><component class="icons" :is="item.icon"></component><span>{{ item.label }}</span></template><el-menu-item-group><el-menu-item v-for="(subItem,subIndex) in item.children" :index="subItem.path" :key="subItem.path"><component class="icons" :is="subItem.icon"></component><span>{{ subItem.label }}</span></el-menu-item></el-menu-item-group></el-sub-menu></el-menu></el-aside>
</template >
<script setup>import {useAllDataStore} from '@/stores'const store = useAllDataStore()const isCollapse = computed(()=>store.state.isCollapse)const width = computed(()=>isCollapse.value?'64px':'180px')import {ref,computed} from 'vue'import { useRouter } from 'vue-router';const router = useRouter()const list = ref([{path:"/home",name:"home",label:"首页",icon:"house",url:"Home"},{path:"/mail",name:"mail",label:"商品管理",icon:"video-play",url:"Mail"},{path:"/user",name:"user",label:"用户管理",icon:"user",url:"User"},{path:"other",label:"其他",icon:"location",children:[{path:"/page1",name:"page1",label:"页面1",icon:"setting",url:"Page1"},{path:"/page2",name:"page2",label:"页面2",icon:"setting",url:"Page2"}]}])const noChildren = computed(()=>list.value.filter(item=>!item.children))const hasChildren = computed(()=>list.value.filter(item=>item.children))
</script>

2.3 导航栏(CommonHeader.vue)

左侧的按钮添加click触发的方法,用于处理菜单折叠事宜。
在这里插入图片描述
在这里插入图片描述

<template><div class="header"><div class="l-content"><el-button size="small" @click="handleCollapse"><component class="icons" is="menu"></component></el-button><el-breadcrumb separator="/" class="bread"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item></el-breadcrumb></div><div class="r-content"><el-dropdown><span class="el-dropdown-link"><img :src="getImageUrl('user')" class="user"/></span><template #dropdown><el-dropdown-menu><el-dropdown-item>个人中心</el-dropdown-item><el-dropdown-item>退出</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></div>
</template><script setup>import {useAllDataStore} from '@/stores'const store = useAllDataStore()const handleCollapse = () => { store.state.isCollapse = !store.state.isCollapse}const getImageUrl= (user) => { return new URL(`../assets/img/${user}.png`,import.meta.url).href}
</script>

3 状态变更的集中管理

不推荐直接修改 store.state.xxx?
(1)违反了“单一状态更新来源”的原则
Pinia(以及Vuex)鼓励将状态的变更逻辑集中管理,而不是在组件中随意修改。
正确做法:使用actions来定义修改状态的方法。
(2)不利于维护和调试
如果多个组件都直接修改state,你很难追踪是谁改了状态。
没有统一的日志、调试工具支持(比如Vue DevTools中看不到“action被调用”)。

3.1 stores/index.js(pinia)

在这里插入图片描述

import { defineStore } from "pinia";
import { ref, computed } from "vue";
function initState(){return {isCollapse:true,}
}
export const useAllDataStore = defineStore("allData", ()=>{//   ref() 相当于state属性//   computed() 相当于getters//   function() 相当于actionsconst state = ref(initState());// 定义 actionfunction toggleCollapse() {state.value.isCollapse = !state.value.isCollapse}return {state,toggleCollapse}
});

3.2 导航栏(CommonHeader.vue)

在这里插入图片描述

4 附录

4.1 computed

const isCollapse = computed(() => store.state.isCollapse)
我想要一个值,它始终等于store.state.isCollapse的当前值,一旦它变了,我就跟着变。const isCollapse = store.state.isCollapse
我现在把store.state.isCollapse的值复制一份,以后它变不变都和我没关系了。

4.2 参考附录

参考elementplus官网地址
参考vue3实现通用后台管理(傻瓜式一步一步记录代码实现过程)

http://www.xdnf.cn/news/18171.html

相关文章:

  • 如何解决C盘存储空间被占的问题,请看本文
  • 数据清洗:数据处理的基石
  • 【完整源码+数据集+部署教程】太阳能面板污垢检测系统源码和数据集:改进yolo11-RVB-EMA
  • IO流与单例模式
  • 【101页PPT】芯片半导体企业数字化项目方案汇报(附下载方式)
  • ArrayList的扩容源码分析
  • 1083. 数列极差问题
  • duiLib 实现鼠标拖动标题栏时,窗口跟着拖动
  • K8s核心组件全解析
  • 产品设计.原型设计
  • 嵌入式 Linux LED 驱动开发实验
  • SpringBoot 整合 Langchain4j:系统提示词与用户提示词实战详解
  • EP1C12F324I7N Altera Cyclone FPGA
  • Python 读取 CSV 文件并删除前五列
  • [安洵杯 2019]Attack
  • Win11更新0x80073712错误解决方法
  • Java 中重载与重写的全面解析(更新版)
  • vscode的使用
  • 10.从开始写LINUX内核——时钟中断
  • 12分区南排烟机,多线模块没电
  • nflsoi 8.16 题解
  • day42_2025-08-16
  • Windows MCP.Net:基于.NET的Windows桌面自动化MCP服务器深度解析
  • 第3章现象表:比较顺序表和链表
  • 记录 GMS 认证相关条件
  • Leetcode 14 java
  • A*寻路算法:原理、实现与优化指南
  • 【Java笔记】synchronized
  • SpringBoot学习日记(九)
  • 游戏客户端性能测试总结