目录
一、Pinia的使用
(1)官网
https://pinia.vuejs.org/zh/introduction.html
(2)快速开始
- 安装
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')
(3)什么是store
Store 是用
defineStore()
定义的,它的第一个参数要求是一个独一无二的名字:import { defineStore } from 'pinia' // 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。 // (比如 `useUserStore`,`useCartStore`,`useProductStore`) // 第一个参数是你的应用中 Store 的唯一 ID。 export const useAlertsStore = defineStore('alerts', { // 其他配置... })
defineStore()
的第二个参数可接受两类值:Setup 函数或 Option 对象。本文将以Setup函数作为第二个参数。
export const useCounterStore = defineStore('counter', () => { const count = ref(0) const doubleCount = computed(() => count.value * 2) function increment() { count.value++ } return { count, doubleCount, increment } })
ref()
就是state
属性computed()
就是getters
function()
就是actions
二、前期准备
(1)组件官网(使用menu菜单)
https://element-plus.org/zh-CN/component/menu.html
(2)使用组件
首先我们在src文件夹下已经创建好了components文件夹,并且创建了CommonAside.vue和CommonHeader.vue文件
//CommonAside.vue
<script setup>
import { ref ,computed} from 'vue';
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'
}
]
}
])
// 返回一个新的数组,其中包含list中所有没有children属性的元素。换句话说,这些元素没有子元素。
const noChildren = computed(() => list.value.filter(item => !item.children))
const hasChildren =computed(() => list.value.filter(item => item.children))
</script>
<template>
<el-aside width="180px">
<el-menu
text-color="#fff"
background-color="#545c64"
>
<h3 >通用后台管理系统</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>
<style lang="less" scoped>
.icons{
width:18px;
height:18px;
margin-right:5px;
color: #fff;
}
.el-menu{
border-right:none;
h3{
line-height:48px;
color:#fff;
text-align:center;
}
span{
color: #fff;
}
}
.el-aside{
height: 100vh;
background-color:#545c64;
}
</style>
//CommonHeader.vue
<script setup>
import { ref ,computed} from 'vue';
const getImageUrl = (user)=>{
return new URL(`../assets/images/${user}.png` , import.meta.url).href
}
</script>
<template>
<div class="header">
<div class="l-content">
<el-button size="small">
<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="../assets/images/${user}.png"> -->
<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>
<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>
(3)效果图
(4)实现效果
我们要实现点击CommonHeader.vue文件下的按钮,实现CommonAside.vue菜单组件的折叠功能。使用menu菜单的Collapse 折叠面板就可以实现
:collapse="isCollapse"
因为涉及到两个不同组件的传值,实现数据的共享,就要使用到pinia,下面开始详细讲解本次例子如何用pinia实现菜单折叠。
(5)Pinia
在安装和引用(main.js)Pinia后,接下来在src文件夹下创建一个stores文件夹,然后新建一个index.js文件
// 导入pinia import { defineStore } from "pinia"; import {ref} from 'vue' // 定义一个方法,全局暴露 function initState(){ } export const useAllDataStore = defineStore('allData', () => { const state = ref(initState()) return { state, } })
三、实战
(1)CommonAside.vue实现折叠基本
1.首先引用之前在stores文件夹写好的index.js
import {useAllDataStore} from '@/stores'
2.然后定义一个store, 调用useAllDataStore()
//定义一个store, 调用useAllDataStore() const store = useAllDataStore()
3.接着对组件进行修改,对h3标签使用v-show进行显示,
- isCollapse是true就是折叠状态,展示“后台”
- 如果是false,就展示“通用后台管理系统”
<el-menu text-color="#fff" background-color="#545c64" :collapse="isCollapse" > <!-- isCollapse是true就是折叠状态,展示后来两个字,如果是false,就展示通用后台管理系统 --> <h3 v-show="!isCollapse">通用后台管理系统</h3> <h3 v-show="isCollapse">后台</h3>
4.接着让isCollapse变成一个响应式,在stores文件夹写好的index.js补充代码,
// 导入pinia import { defineStore } from "pinia"; import {ref} from "vue" // 定义一个方法,全局暴露 function initState(){ return { isCollapse : false } } export const useAllDataStore = defineStore('allData', () => { const state = ref(initState()) return { state, } })
然后回到CommonAside.vue,使用
const isCollapse = computed(()=>store.state.isCollapse)
看效果:
isCollapse : false
isCollapse : true
5.实现宽度变化,把宽度设置为响应式。
<el-aside :width="width">
const width = computed(()=>store.state.isCollapse ? '64px' : '180px')
看效果:
isCollapse : false
isCollapse : true
最后设置 isCollapse : false,方便后续操作
(2)CommonHeader.vue实现按钮点击后折叠
(1)给按钮添加点击事件,绑定handleCollpase方法。
<el-button size="small" @click="handleCollpase">
(2)定义该方法,实现Pinia操作
import {useAllDataStore} from '@/stores' const store = useAllDataStore() const handleCollpase = ()=>{ store.state.isCollapse = !store.state.isCollapse }
(3)看效果
发现点击该按钮,效果确实生效