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

八、vue3后台项目系列——封装layout页面下切换组件Appmain

先上组件代码再做解释:

在layout文件下创建components文件夹,创一个Appmain组件,主要用来控制页面的切换,缓存需要缓存的页面状态,主要是搭配标签tag

一、Appmain组件

<template><section class="app-main"><transition name="fade-transform" mode="out-in"><keep-alive :include="cachedViews"><router-view :key="key" /></keep-alive></transition></section>
</template><script setup>
import { ref,onMounted,computed } from 'vue'
import { useTagsViewStore } from '@/store';
import { useRoute } from 'vue-router';
// 获取路由实例
const route = useRoute();
const tagsViewStore = useTagsViewStore();
// 获取缓存标签页面的数组
const cachedViews = computed(() => {return tagsViewStore.cachedViews; // Pinia 写法
});
// 获取当前展示的页面
const key = computed(() => {return route.path;
});
</script><style lang="scss" scoped>
// 1. 基础布局:main 区域的高度适配(排除导航栏高度)
.app-main {min-height: calc(100vh - 50px); // 视口高度 - 导航栏高度(50px),确保满屏width: 100%; // 宽度占满父容器position: relative; // 为子元素绝对定位做准备overflow: hidden; // 隐藏超出容器的内容,避免滚动条冗余
}// 2. 当导航栏是固定定位时(fixed-header),给 main 加顶部内边距,避免内容被遮挡
.fixed-header+.app-main {padding-top: 50px; 
}// 3. 当存在标签页(hasTagsView)时,重新计算高度(导航栏50px + 标签页34px = 84px)
.hasTagsView {.app-main {min-height: calc(100vh - 84px); }// 固定导航栏 + 标签页时,顶部内边距同步增加.fixed-header+.app-main {padding-top: 84px;}
}
</style><style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {.fixed-header {padding-right: 15px;}
}
</style>

二、创建tagsViewStore模块状态管理仓库

在src/store/modules/tagsViewStore中写入:

import { defineStore } from 'pinia';export const useTagsViewStore = defineStore('tagsView', {// 状态定义(替代Vuex的state)state: () => ({visitedViews: [],  // 已访问的标签页列表cachedViews: []    // 需要缓存的组件名称列表}),// 方法定义(替代Vuex的mutations和actions)actions: {// 添加访问过的标签页addVisitedView(view) {// 如果已存在相同路径的标签,直接返回if (this.visitedViews.some(v => v.path === view.path)) return;this.visitedViews.push(Object.assign({}, view, {title: view.meta.title || 'no-name'  // 确保标题存在}));},// 添加需要缓存的标签页addCachedView(view) {// 如果已缓存或设置了不缓存,直接返回if (this.cachedViews.includes(view.name) || view.meta.noCache) return;this.cachedViews.push(view.name);},// 同时添加访问和缓存标签addView(view) {this.addVisitedView(view);this.addCachedView(view);},// 删除指定访问标签delVisitedView(view) {return new Promise(resolve => {const index = this.visitedViews.findIndex(v => v.path === view.path);if (index > -1) {this.visitedViews.splice(index, 1);}resolve([...this.visitedViews]);  // 返回更新后的列表});},// 删除指定缓存标签delCachedView(view) {return new Promise(resolve => {const index = this.cachedViews.indexOf(view.name);if (index > -1) {this.cachedViews.splice(index, 1);}resolve([...this.cachedViews]);  // 返回更新后的列表});},// 同时删除访问和缓存标签delView(view) {return new Promise(resolve => {this.delVisitedView(view);this.delCachedView(view);resolve({visitedViews: [...this.visitedViews],cachedViews: [...this.cachedViews]});});},// 删除其他访问标签(保留当前和固定标签)delOthersVisitedViews(view) {return new Promise(resolve => {this.visitedViews = this.visitedViews.filter(v => {return v.meta.affix || v.path === view.path;});resolve([...this.visitedViews]);});},// 删除其他缓存标签(只保留当前标签)delOthersCachedViews(view) {return new Promise(resolve => {const index = this.cachedViews.indexOf(view.name);if (index > -1) {this.cachedViews = this.cachedViews.slice(index, index + 1);} else {this.cachedViews = [];}resolve([...this.cachedViews]);});},// 删除其他所有标签delOthersViews(view) {return new Promise(resolve => {this.delOthersVisitedViews(view);this.delOthersCachedViews(view);resolve({visitedViews: [...this.visitedViews],cachedViews: [...this.cachedViews]});});},// 删除所有访问标签(保留固定标签)delAllVisitedViews() {return new Promise(resolve => {const affixTags = this.visitedViews.filter(tag => tag.meta.affix);this.visitedViews = affixTags;resolve([...this.visitedViews]);});},// 清空所有缓存标签delAllCachedViews() {return new Promise(resolve => {this.cachedViews = [];resolve([...this.cachedViews]);});},// 删除所有标签delAllViews() {return new Promise(resolve => {this.delAllVisitedViews();this.delAllCachedViews();resolve({visitedViews: [...this.visitedViews],cachedViews: [...this.cachedViews]});});},// 更新访问标签信息updateVisitedView(view) {const index = this.visitedViews.findIndex(v => v.path === view.path);if (index > -1) {this.visitedViews[index] = Object.assign({}, this.visitedViews[index], view);}}}
});

在主index.js文件导入

export * from "@/store/modules/applicationStore";
export * from "@/store/modules/tagsViewStore";

三、统一导出layout下的组件

我们在components下创建一个index.js文件,用于导入layout下面的组件,虽然我们现在只有一个组件,但是后面我们可以使用解构的写法进行导入组件进行使用。

index.js

export { default as AppMain } from './AppMain/index.vue';

四、在layout的index.vue组件中导入

<template><div :class="classObj" class="app-wrapper"><!-- 移动端打开侧边栏时,点击遮罩关闭侧边栏 --><div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /><!-- 侧边栏 --><!-- <sidebar class="sidebar-container" /> --><!-- 主体部分 --><div :class="{hasTagsView:needTagsView}" class="main-container"><!-- 头部 --><div :class="{'fixed-header':fixedHeader}"><!-- 顶部栏 --><!-- <navbar /> --><!-- 标签 --><!-- <tags-view v-if="needTagsView" /> --></div><!-- 显示当前路由页面 --><app-main /></div></div>
</template><script setup>
import { ref,onMounted } from 'vue'
import { useAppStore } from '@/store';
import { AppMain } from './components'
const appStore = useAppStore();
// 点击外部的处理函数
const handleClickOutside = () => {// 直接调用store中的方法,参数直接传递(无需像Vuex那样用对象包裹)appStore.closeSideBar(false);
};</script><style lang="scss" scoped>
@use "@/styles/mixin.scss" as *;
.app-wrapper {@include clearfix;position: relative;height: 100%;width: 100%;&.mobile.openSidebar {position: fixed;top: 0;}}.drawer-bg {background: #000;opacity: 0.3;width: 100%;top: 0;height: 100%;position: absolute;z-index: 999;}.fixed-header {position: fixed;top: 0;right: 0;z-index: 9;width: calc(100% - var(--sideBarWidth));transition: width 0.28s;}.hideSidebar .fixed-header {width: calc(100% - 54px)}.mobile .fixed-header {width: 100%;}</style>


文章转载自:

http://nWckoDZH.hphfy.cn
http://dJHWFyrm.hphfy.cn
http://JDMTRx3o.hphfy.cn
http://EX7tEGIz.hphfy.cn
http://z3jOq3ep.hphfy.cn
http://OFAi5l9D.hphfy.cn
http://B8I3iaxL.hphfy.cn
http://8WgYUmDN.hphfy.cn
http://TE12k7ey.hphfy.cn
http://YteBlvoZ.hphfy.cn
http://AWS8YGUB.hphfy.cn
http://fn4ehQfh.hphfy.cn
http://1wnvFCQS.hphfy.cn
http://yfgdjcVt.hphfy.cn
http://AQoLwUZc.hphfy.cn
http://9c1b5NOY.hphfy.cn
http://Ys3ZfPtd.hphfy.cn
http://3S7pxmew.hphfy.cn
http://aUpZrcut.hphfy.cn
http://SpbLWe8w.hphfy.cn
http://FEhDlMhb.hphfy.cn
http://Oljvmxp6.hphfy.cn
http://UTwCs8iF.hphfy.cn
http://akB3RSYS.hphfy.cn
http://8EF60nDP.hphfy.cn
http://XkLecUkB.hphfy.cn
http://okKecjuw.hphfy.cn
http://N3Uav1kn.hphfy.cn
http://Zb8iV3Uy.hphfy.cn
http://Vw3Xgoaw.hphfy.cn
http://www.dtcms.com/a/384620.html

相关文章:

  • 学习React-12-useEffect
  • MFC_Button
  • [K8S学习笔记]YAML相关
  • 贪心算法在物联网能耗优化中的应用
  • 使用paddlepaddle-Gpu库时的一个小bug!
  • 从 Linux 到 Kubernetes:操作系统的演变与云原生未来
  • Java网络编程:(socket API编程:TCP协议的 socket API -- 服务器端处理请求的三个步骤)
  • 新能源汽车总装车间案例:四台S7-1200通过无线网桥同步控制16组ET 200SP的秘诀
  • k8s事件驱动运维利器 shell operator
  • GitHub Actions 部署配置
  • java后端工程师进修ing(研一版‖day45)
  • k8s核心资料基本操作
  • Redis 在电商系统中的应用:高并发场景下的架构艺术
  • RK3588:MIPI底层驱动学习——芯外拾遗第一篇:从四个模块到整个“江湖”
  • K8S里的“豌豆荚”:Pod
  • OpenStack 管理与基础操作学习笔记(一):角色、用户及项目管理实践
  • 大数据毕业设计选题推荐-基于大数据的金融数据分析与可视化系统-Spark-Hadoop-Bigdata
  • Python爬虫实战:研究Pandas,构建期货数据采集和分析系统
  • 软考中级习题与解答——第六章_计算机硬件基础(3)
  • Nvidia显卡架构解析与cuda应用生态浅析
  • AppStore 如何上架?iOS 应用发布全流程、uni-app 打包上传 ipa、App Store 审核与多工具组合实战指南
  • 贪心算法应用:卫星链路调度问题详解
  • 基于https的数据加密技术
  • 自学嵌入式第四十一天:单片机-中断
  • 二分图 系列
  • DDAC工作流的PyCharm项目前置准备清单
  • 【Kubernetes】K8s 集群外服务配置 Service 访问
  • RESTFul API接口设计指南_V2
  • Linux第十七讲:应用层自定义协议与序列化
  • ESLint 自定义规则开发