Vue3+Vite+TypeScript+Element Plus开发-17.Tags-组件构建
系列文档目录
Vue3+Vite+TypeScript安装
Element Plus安装与配置
主页设计与router配置
静态菜单设计
Pinia引入
Header响应式菜单缩展
Mockjs引用与Axios封装
登录设计
登录成功跳转主页
多用户动态加载菜单
Pinia持久化
动态路由 -动态增加路由
动态路由-动态删除路由
路由守卫-无路由跳转404
路由守卫-未登录跳转登录界面
登录退出
Tags-组件构建
Tags-与菜单联动
Pinia持久化优化
按钮权限
客制按钮组件
客制Table组件
客制Form组件
国际化
配置文件
Tags-与菜单联动
文章目录
目录
系列文档目录
文章目录
前言
Tags组件构建
main界面调整
效果首现
Tags存储初始化
Tags组件初始化调整
运行效果
后续
前言
在上一章节中,详细探讨了登录与退出机制的构建。本章节将聚焦于 Tags 组件的开发,其核心目标是:当用户点击菜单项时,能够在 main 区域以 Tab 的形式动态呈现对应内容。
Tags组件构建
在 components 文件夹中新建 MainTagsCont.vue 文件
代码如下:
<template><div class="tabs"><el-tab v-for="(item,index) in tabs":key="index":label="item.label":name="item.name":icon="item.icon":path="item.path":closable="item.name !== 'home'":effect="route.name===item.name?'dark':'plain'">{{ item.label }}</el-tab></div>
</template>
<script lang="ts" setup>
import{ effect, ref } from "vue"
import { useRoute } from "vue-router";const tabs=ref([{path:"/home",name:"home",label:"首页",icon:"home"}])
const route=useRoute()
</script>
<style scoped>.tabs{margin: 20px 0 0 20px;
}
.el-tab{margin-right: 10px;
}
</style>
main界面调整
修改 main.vue 文件在 main.vue 文件中导入 MainTagsCont组件,并在 <el-header> 和 <el-main> 之间插入 <MainTagsCont
/> 组件。
<el-header><MainHdrCont /></el-header><MainTagsCont />
<el-main><router-view></router-view>
</el-main>
调整后完整代码:
<template><div class="common-layout"><el-container class="container-aside" ><el-aside :width="ContAsideWidth"><MainAsideCont /> </el-aside><el-container><el-header><MainHdrCont /></el-header><MainTagsCont /><el-main><router-view></router-view></el-main></el-container></el-container></div>
</template>
<script lang="ts" setup>
import { defineComponent, computed , onMounted} from 'vue';
import MainAsideCont from '@/components/MainAsideCont.vue';
import MainHdrCont from '@/components/MainHdrCont.vue'
import MainTagsCont from '@/components/MainTagsCont.vue';
import { useAllDataStore } from '@/stores';
import { ReloadData } from '@/stores';const store = useAllDataStore();const ContAsideWidth = computed(() => {
return store.isCollapse ? '60px' : '180px';
});// 在组件挂载时调用 ReloadData
onMounted(() => {// ReloadData();
});
</script><style lang="less" scoped>
.common-layout {height: 100%; /* 设置整个布局的高度为 100%,确保布局占满整个视口 */width: 100%; /* 设置整个布局的宽度为 100%,确保布局占满整个视口 */.container-aside {height: 100%; /* 确保内部的 el-container 也占满整个父容器的高度 */}.el-header {background-color: #141515 ; /* 设置表头的背景色为深黑色 fff 141515*/color: #fff; /* 设置表头文字颜色为白色,以便在深色背景上更清晰 */display: flex; /* 使用 flex 布局,方便对齐内容 */align-items: center; /* 垂直居中对齐内容 */justify-content: center; /* 水平居中对齐内容 */font-size: 18px; /* 设置文字大小为 18px */font-weight: bold; /* 设置文字为加粗 */}.el-aside {background-color:rgba(242, 242, 242, 0.19); /* 设置侧边栏的背景色为浅灰色 */color: #333; /* 设置侧边栏文字颜色为深灰色 */display: flex; /* 使用 flex 布局,方便对齐内容 */ align-items: center; /* 垂直居中对齐内容 */justify-content: center; /* 水平居中对齐内容 */font-size: 16px; /* 设置文字大小为 16px */font-weight: normal; /* 设置文字为正常粗细 */height: 100%; /* 确保侧边栏高度占满 */}.el-main {background-color: #fff; /* 设置主内容区域的背景色为白色 */color: #333; /* 设置主内容区域文字颜色为深灰色 */padding: 20px; /* 添加内边距,使内容不紧贴边缘 */font-size: 14px; /* 设置文字大小为 14px */}
}
</style>
效果首现
登录后,会显示 Tags 标签组件首页
Tags存储初始化
在构建 Tags 组件 时,Tags 的初始数据在组件内部进行初始化。为了实现对 Tags 的动态调整,使用 Pinia 来管理 Tags 的状态,并通过 Pinia 的状态管理功能对 Tags 的初始数据进行统一管理和调整。
tabs:[{path:"/home",name:"home",label:"home",icon:"home"}],// tabssetTabsData(tabs: any){this.tabs = tabs},getTabsData(): [] {return this.tabs;},
调整后完整语句:
// src/stores/index.tsimport { defineStore } from 'pinia';
import router from '../router';
import type { Component } from 'vue';
import { get } from 'http';type Modules = Record<string, () => Promise<{ default: Component }>>;// 定义公共 store
export const useAllDataStore = defineStore('useAllData', {// 定义状态state: () => ({isCollapse: false, // 定义初始状态username: '',token_key: '',menuData:[],tabs:[{path:"/home",name:"home",label:"home",icon:"home"}],}),// 定义 actionsactions: {// 设置用户名setUsername(username: string) {this.username = username;},// 获取用户名getUsername(): string {return this.username;},// 设置 token_keysetTokenKey(token_key: string) {// sessionStorage.setItem('useAllData-session-store', JSON.stringify({ token_key: token_key, menuData: this.menuData}));this.token_key = token_key;},// 获取 token_keygetTokenKey(): string {/*const sessionData = sessionStorage.getItem('useAllData-session-store');console.log(sessionData)if (sessionData) {const data = JSON.parse(sessionData);this.token_key = data.token_key;this.menuData = data.menuData;}else{this.token_key = ''}*/return this.token_key;},// 设置菜单数据setMenuData(menuData: any){// sessionStorage.setItem('useAllData-session-store', JSON.stringify({ token_key: this.token_key, menuData: menuData}));addRouter(menuData)this.menuData = menuData},// 获取菜单数据getMenuData(): [] {return this.menuData;},// tabssetTabsData(tabs: any){this.tabs = tabs},getTabsData(): [] {return this.tabs;},// 登出方法logout() {sessionStorage.removeItem('useAllData-store'); // 清除 sessionStorage 中的数据/*this.username = '';this.token_key = '';this.menuData = [];*/router.push({ name: 'login' }); // 重定向到登录页面},},persist: {enabled: true,key: 'useAllData-store',storage: sessionStorage, // // localStorage sessionStoragepaths: ['token_key'], // 指定持久化的字段},/*persist: {enabled: true,strategies: [{key: 'useAllData-store',storage: sessionStorage,// localStorage sessionStoragepaths: ['token_key','menuData'], // 指定需要持久化的字段},],},*/});function addRouter(menuData: any){const routerList=router.getRoutes()const modules: Modules = import.meta.glob('../views/**/*.vue') as Modules;const routerArr=[]menuData.forEach((item:any) => {// console.log(item) if(item.children){item.children.forEach((child:any) => {const componentPath = `../${child.path}.vue`;const module = modules[componentPath];if (module) {/*module().then(({ default: component }) => {child.component = component;});*/child.component = module;routerArr.push(child)}});}else{const componentPath = `../${item.path}.vue`;const module = modules[componentPath];if(module){item.component = module;routerArr.push(item)}}});// 增加删除路由routerList.forEach((item:any) => {if (item.name === 'main' || item.name === 'home' || item.name === '404' || item.name === 'login'|| item.name === 'error'|| item.name === 'undefined'|| item.path === '/'|| item.path === '/main') returnrouter.removeRoute(item.name)});routerArr.forEach((item:any) => {router.addRoute('main',{path: item.index,name: item.label,component: item.component,});})
const routerListLast=router.getRoutes()
console.log(routerListLast)}export function ReloadData() {const store = useAllDataStore();const menuData = store.getMenuData();addRouter(menuData);}
Tags组件初始化调整
Tags 的初始化内容主要通过 Pinia store 获取。
const store = useAllDataStore();const tabs=computed(() => store.getTabsData());
调整后语句:
<template><div class="tabs"><el-tab v-for="(item,index) in tabs":key="index":label="item.label":name="item.name":icon="item.icon":path="item.path":closable="item.name !== 'home'":effect="route.name===item.name?'dark':'plain'">{{ item.label }}</el-tab></div>
</template>
<script lang="ts" setup>
import{ effect, ref ,computed} from "vue"
import { useRoute } from "vue-router";
import { useAllDataStore } from '@/stores';
const store = useAllDataStore();const tabs=computed(() => store.getTabsData());
const route=useRoute()
</script>
<style scoped>.tabs{margin: 20px 0 0 20px;
}
.el-tab{margin-right: 10px;
}
</style>
运行效果
后续
本章节已完成了 Tags 组件的初步构建。在下一章节中,我们将继续完善 Tags 组件,使其与菜单实现完整联动。