Vue实训---4-使用Pinia实现menu菜单展示/隐藏

0.menu菜单展示/隐藏实现方法

Menu 菜单 | Element Plus中,当:collapse="isCollapse"其中isCollapse的值为true时菜单栏隐藏,当isCollapse的值为false时菜单栏显示。接下来使用pinia实现CommonAside.vue和CommonHeader.vue组件之间数据的共享,即点击CommonHeader.vue组件中的mune按钮,展示隐藏CommonAside.vue组件中的菜单栏。

1.pinia简介

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。简介 | Pinia

2.pinia安装

在vscode终端中输入: npm install pinia

3.在main.js中使用pinia

// 引入 pinia
import { createPinia } from 'pinia'
// 创建 pinia 实例
const pinia = createPinia()


// 注入 pinia
app.use(pinia)

4.在src文件夹下创建stores文件夹,在其中创建index.js并编写代码

import { defineStore } from "pinia";
import { ref, computed, reactive } from "vue";

// // https://pinia.vuejs.org/zh/core-concepts/ 官方文档示例代码
// // 定义 store 的一种语法。我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
// // 创建一个 store
// export const useAllDateStore = defineStore("allDate", () => {
//   // 定义响应式属性
//   const isCollapse = ref(false);

//   //   // 定义方法来切换布尔值
//   function toggleCollapse() {
//     isCollapse.value = !isCollapse.value;
//   }

//   // 返回 store 对象
//   return {
//     isCollapse,
//     toggleCollapse,
//   };
//   // const count = ref(0)
//   // const doubleCount = computed(() => count.value * 2)
//   // function increment() {
//   //   count.value++
//   // }
//   // return { count, doubleCount, increment }
// });

// 你可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods)。
export const useAllDateStore = defineStore("allDate", {
  state: () => ({
    isCollapse: false,
    // count: 0,
    // name: "Eduardo",
  }),
  getters: {
    // doubleCount: (state) => state.count * 2,
  },
  actions: {
    toggleCollapse() {
      this.isCollapse = !this.isCollapse;
    },
  },
});

5.修改CommonAside.vue

我们要在组件间传递的值是"isCollapse",修改CommonAside.vue:

CommonAside.vue所有代码:

<template>
    <!-- 首先最外层是Main.vue中注释的<el-aside width="200px" class="el-aside">Aside</el-aside>,我们将侧边栏改成我们自定义的组件,通过common-aside引入我们自己写的组件 -->
    <el-aside :width="width" class="el-aside">
        <el-menu background-color="#545c64" text-color="#fff" :collapse="isCollapse">
            <!-- 写菜单栏的大标题------------通用后台管理系统 -->
            <h3 v-show="!isCollapse">通用后台管理系统</h3>
            <h3 v-show="isCollapse">后台</h3>
            <!-- 循环遍历菜单栏 -->
            <!-- 1.没有子菜单的遍历 -->
            <el-menu-item v-for="item in noChildren" :key="item.path" :index="item.path">
                <!-- <el-icon><icon-menu /></el-icon> -->
                <!-- 动态获取icon图标 -->
                <component :is="item.icon" class="icons"></component>
                <!-- 显示文字内容 -->
                <span>{{ item.label }}</span>
            </el-menu-item>
            <!-- 2.有子菜单的遍历 -->
            <el-sub-menu v-for="item in hasChildren" :key="item.path" :index="item.path">
                <template #title>
                    <!-- 动态获取icon图标 -->
                    <component :is="item.icon" class="icons"></component>
                    <!-- 显示文字内容 -->
                    <span>{{ item.label }}</span>
                </template>
                <!-- 分组 -->
                <el-menu-item-group>
                    <!-- 循环遍历子菜单 -->
                    <el-menu-item v-for="child in item.children" :key="child.path" :index="child.path">
                        <!-- 动态获取icon图标 -->
                        <component :is="child.icon" class="icons"></component>
                        <!-- 显示文字内容 -->
                        <span>{{ child.label }}</span>
                        >
                    </el-menu-item>
                </el-menu-item-group>
            </el-sub-menu>
        </el-menu>
    </el-aside>
</template>

<script setup>
import { ref, computed } from 'vue'
import { storeToRefs } from 'pinia';
import { useAllDateStore } from '@/stores/index';
// 获取 store 实例
const store = useAllDateStore();
// 使用 storeToRefs 解构响应式属性
const { isCollapse } = storeToRefs(store);
// 根据 isCollapse 来计算宽度
const width = computed(() => isCollapse.value ? '64px' : '200px')

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))
</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: 100%;
    background-color: #545c64;
}
</style>

6.修改CommonHeader.vue

CommonHeader.vue完整代码:

<template>
    <div class="header">
        <!-- 左侧点击四个点的Menu按钮具有折叠菜单栏的功能,右侧user的头像,头像有下栏菜单 -->
        <div class="l-content">
            <el-button size="small" @click="toggleCollapse">
                <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">
                    <!-- Dropdown List
                    <el-icon class="el-icon--right">
                        <arrow-down />
                    </el-icon> -->
                    <!-- 将此部分内容换成我们要显示的用户头像图片(my-vue-project\src\assets\images\user.png) -->
                    <img :src="getImageUrl('user')" alt="用户头像" 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'
// 通过参数user的名字可以获取动态的图片的url
// 通过new URL()方法可以创建并返回一个URL对象,用来获取图片的url(百度new URL MDN)
// 通过import.meta.url可以获取当前模块的url
const getImageUrl = (user) => {
    return new URL(`../assets/images/${user}.png`, import.meta.url).href
}

import { useAllDateStore } from '@/stores/index';
// 获取 store 实例
const store = useAllDateStore();
// 使用 store 中的 toggleCollapse 方法
function toggleCollapse() {
    store.toggleCollapse()
}
</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(.bread span) {
    color: #fff !important;
    cursor: pointer !important;
}
</style>

显示效果:

点击header上的四个点的menu按钮后:

完成!

附所有代码

通过百度网盘分享的文件:my-vue-project.zip

链接:https://pan.baidu.com/s/1BWVbHXtlagH3oHbrVENp1A?pwd=6666

提取码:6666

相关推荐
Fetters0432 分钟前
一篇快速上手 Axios,一个基于 Promise 的网络请求库(涉及原理实现)
前端·ajax·axios·promise
蒟蒻的贤35 分钟前
vue11.22
开发语言·前端·javascript
爱上语文37 分钟前
Axios案例练习
前端·javascript·css·html
河畔一角38 分钟前
升级react@18.3.1后,把我坑惨了
前端·react.js·低代码
天天进步201540 分钟前
Vue 3 + Vite:构建闪电般快速的开发环境
前端·javascript·vue.js
Dragon Wu1 小时前
前端框架 Redux tool RTK 总结
前端·javascript·前端框架
yqcoder1 小时前
reactflow 中 useStoreApi 模块作用
前端·javascript
williamdsy1 小时前
【vue】关于异步函数使用不当导致的template内容完全无法渲染的问题
前端·javascript·vue.js
2402_839708051 小时前
第十章:作业
开发语言·前端·javascript
诗水人间1 小时前
前后端分离,解决vue+axios跨域和proxyTable不生效等问题
前端·javascript·vue.js·springboot·springsecurity·跨域·cros