文章目录
- vue后台管理系统从0到1(6)引入pinia实现折叠功能
- 分析:
- 安装并使用 pinia
vue后台管理系统从0到1(6)引入pinia实现折叠功能
分析:
首先,接着上一期,我们项目启动起来应该是这个样子
我们需要实现的功能是单机首页左边的按钮,实现把侧边栏收起来或者展开
这里可以想一想,侧边栏和这个按钮的关系
侧边栏属于 aside
下面这个按钮在header里面,所以他们两个甚至连兄弟组件都算不上
这里我们需要在不同的组件之间进行传输变量值,或者说共享,在vue2的时候,我们会用到 vuex
但是这里是 vue3 了,我们使用 pinia进行这个操作
安装并使用 pinia
打开pinia的官方网址
pinia官网
第一步安装:
yarn add pinia
# 或者使用 npm
npm install pinia
在 main.js 中创建并使用
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
这里重构 main.js 中的代码:
import { createApp } from 'vue'
import App from './App.vue'
import '@/assets/less/index.less'
import router from "@/router/index.js";
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.use(ElementPlus)
app.use(router);
app.mount('#app');
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
在 src 中新建 stores/index.js
并且引入 pinia 的配置代码在 index.js
import {defineStore} from "pinia";
import {ref} from "vue";
function inState(){
return {
isCollapse:false,
}
}
export const useAllDataStore = defineStore("allData",() =>{
const state = ref(inState());
return{
state,
};
})
不懂自行看 pinia 的官网或者 gpt
这里需要使用 collapse 这个属性在侧边栏中控值是否折叠
在header中对这个按钮加入点击绑定
首先找到它的位置,在它的标签上加上 @click=“方法”
然后对方法实现
以下是本组件重构代码
CommonHeader.vue
<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 {ref, computed} from 'vue';
import {useRouter} from 'vue-router';
import {useAllDataStore} from "@/stores/index.js";
const router = useRouter();
const list = ref([
{path: '/home', name: 'home', label: '首页', icon: 'el-icon-house', url: 'Home'},
{path: '/mall', name: 'mall', label: '商品管理', icon: 'el-icon-video-play', url: 'Mall'},
{path: '/user', name: 'user', label: '用户管理', icon: 'el-icon-user', url: 'User'},
{
path: '/other', label: '其他', icon: 'el-icon-location',
children: [
{path: '/page1', name: 'page1', label: '页面1', icon: 'el-icon-setting', url: 'Page1'},
{path: '/page2', name: 'page2', label: '页2', icon: 'el-icon-setting', url: 'Page2'}
]
}
]);
const getImageUrl = (user) => {
return new URL(`../assets/images/${user}.png`, import.meta.url).href;
};
const store = useAllDataStore();
const handleCollapse = ()=>{
store.state.isCollapse = !store.state.isCollapse
}
</script>
<style lang="less" scoped>
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
background-color: #333;
}
.icons {
width: 20px;
height: 20px;
}
.l-content {
display: flex;
align-items: center;
.el-button{
margin-right: 20px;
}
}
.r-content {
.user{
width: 40px;
height: 40px;
border-radius: 50%;
}
}
/* 注意::deep() 是一个 Vue.js 中的作用域穿透伪元素,用于在 scoped CSS 中访问子组件的样式。
但它不是标准的 CSS 语法,且在新版本的 Vue.js 中可能已经被废弃或替换。
如果这段代码是在 Vue.js 项目中使用的,请确保你的项目支持这种语法。
此外,由于选择器中包含特殊字符(如点号和括号),你可能需要对其进行适当的转义或使用其他方法来实现相同的效果。
但在这里,为了保持原始信息的完整性,我保留了这段代码的原样。 */
:deep(.bread span) {
color: #fff !important;
cursor: pointer !important;
}
</style>
在侧边栏组件中,当我们的侧边栏组件缩回去时,我们需要把上面的标题还有侧边栏的 widith 变小,这里也需要获取到 pinia 中 collaspe 的状态
把 widith 使用变量替换,加入 v-show 来管理伸缩不同的字样
然后也是一样,需要或许到 collapse 的状态
导入方法获取状态
定义 store 并且获取到状态
重构 CommonAside.vue 后
<template>
<el-aside :width="width">
<el-menu @select="handleMenuSelect" background-color="#545c64" text-color="#fff" :collapse="isCollapse">
<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
v-for="subItem in item.children"
:index="subItem.path"
:key="subItem.path"
>
<component class="icons" :is="subItem.icon"></component>
<span>{{ subItem.label }}</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useRouter } from 'vue-router';
import {useAllDataStore} from "@/stores/index.js";
const router = useRouter();
const list = ref([
{ path: '/home', name: 'home', label: '首页', icon: 'house', url: 'Home' },
{ path: '/mall', name: 'mall', label: '商品管理', icon: 'video-play', url: 'Mall' },
{ 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));
const store = useAllDataStore();
const isCollapse = computed(()=>store.state.isCollapse)
const width = computed(()=>store.state.isCollapse ? "64px":"200px")
const handleMenuSelect = (index) => {
const item = list.value.find(item => item.path === index) ||
list.value.flat().find(item => item.path === index);
if (item) {
router.push(item.path);
}
};
</script>
<style lang="less" scoped>
.icons {
width: 18px;
height: 18px;
margin-right: 5px;
}
.el-menu{
border-right: none;
h3{
line-height: 48px;
color: #fff;
text-align: center;
}
}
.el-aside{
height: 10000px;
background-color: #545c64;
}
</style>
重启项目:
发现点一下可以伸缩侧边栏了,但是我们的 header 出现问题,并没有随着侧边栏的伸缩而伸缩,本期先到这