Layout 布局组件快速搭建

文章目录

  • 设置主题样式变量
  • 封装公共布局组件
    • 封装 Logo 组件
    • 封装 Menu 菜单组件
    • 封装 Breadcrumb 面包屑组件
    • 封装 TabBar 标签栏组件
    • 封装 Main 内容区组件
    • 封装 Footer 底部组件
    • 封装 Theme 主题组件
  • 经典布局
  • 水平布局
  • 响应式布局
  • 搭建 Layout 布局组件
  • 添加 Layout 路由配置
  • 启动项目

设置主题样式变量

  1. 创建主题变量文件:src/assets/styles/theme.scss

  2. 添加页面布局组件用到的变量:

    :root {--os-layout-aside-width: 224px; // 侧边栏宽度--os-layout-logo-height: 56px; // 头部高度--os-layout-header-height: 56px; // 头部高度--os-layout-header-menu-width: 300px; // 头部菜单宽度--os-layout-footer-height: 40px; // 底部高度--os-layout-tab-height: 40px; // 底部高度
    }
    
  3. 设置全局滚动条样式:

    /* scroll bar */
    ::-webkit-scrollbar {width: 6px;height: 6px;
    }::-webkit-scrollbar-thumb {background-color: var(--el-border-color-darker);border-radius: 20px;
    }
    
  4. 在统一管理和维护项目的样式文件src/assets/styles/index.scss中导入主题样式文件:

    @import "theme.scss";
    

注:统一管理和维护项目的样式文件src/assets/styles/index.scss需在mian.ts中导入,注意导入顺序。

封装公共布局组件

封装 Logo 组件

  1. 创建 Logo 组件:src/layouts/components/Logo/index.vue

  2. 通过import.meta.env获取.env文件中定义的环境变量,环境变量使用详情跳转认识和使用 Vite 环境变量配置:

    <script setup lang="ts">
    const app_title = import.meta.env.VITE_APP_TITLE
    </script>
    
  3. Logo 组件内容,添加 Logo 图标和项目标题:

    <template><!-- logo 容器 --><div class="logo-container"><!--  logo 图标 --><svg-icon width="32px" height="32px" name="logo" /><!-- 应用标题,只在中等及以上屏幕尺寸上可见 --><span class="logo-title hidden md:block">{{ app_title }}</span></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="postcss">
    .logo-container {@apply flex items-center justify-center;height: var(--os-layout-logo-height);width: var(--os-layout-aside-width);.logo-title {@apply text-lg font-bold subpixel-antialiased;@apply bg-clip-text text-transparent bg-gradient-to-r from-pink-500 to-violet-500;}
    }
    </style>
    

封装 Menu 菜单组件

  1. 创建 Menu 菜单组件:src/layouts/components/Menu/index.vue

  2. el-menu 组件中使用 props 来控制 mode 属性,可以实现菜单的不同显示模式(如 verticalhorizontal):

    <script setup lang="ts">
    const props = defineProps<{mode?: 'vertical' | 'horizontal'
    }>()
    </script>
    
  3. 使用 ElementPlus 的 el-menu 菜单组件搭建垂直菜单:

    <template><!-- 菜单容器 --><div class="menu-container"><!-- Element UI 菜单组件 --><el-menuclass="os-menu":mode="props.mode"><!-- 一级菜单 --><el-sub-menu index="1"><!-- 一级菜单标题 --><template #title><span>Navigator One</span></template><!-- 二级菜单 --><el-menu-item index="1-1">item one</el-menu-item><el-menu-item index="1-2">item two</el-menu-item></el-sub-menu><!-- 一级菜单 --><el-menu-item index="2"><span>Navigator Two</span></el-menu-item></el-menu></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="postcss">
    .menu-container{background-color: var(--el-menu-bg-color);.os-menu{@apply border-0;&.el-menu--horizontal{height: calc(var(--os-layout-logo-height) - 1px);}}
    }
    </style>
    

封装 Breadcrumb 面包屑组件

  1. 创建 src/layouts/components/Breadcrumb/index.vue

  2. 使用 ElementPlus el-breadcrumb 面包屑组件:

    <template><el-breadcrumb separator="/" class="breadcrumb-container"><el-breadcrumb-item :to="{ path: '/' }">homepage</el-breadcrumb-item><el-breadcrumb-item>management</el-breadcrumb-item><el-breadcrumb-item>list</el-breadcrumb-item><el-breadcrumb-item>detail</el-breadcrumb-item></el-breadcrumb>
    </template>
    
  3. 添加样式:

    <style scoped lang="postcss">
    .breadcrumb-container {display: flex;flex-wrap: nowrap; /* 防止换行 */overflow: hidden; /* 横向滚动溢出处理 */padding-right: 12px;
    }
    </style>
    

封装 TabBar 标签栏组件

  1. 创建 src/layouts/components/TabBar/index.vue

  2. 生成 TabBar 标签数据:

    <script setup lang="ts">
    const tabs = Array(1).fill({label: 'About',name: 'about',icon: 'About',path: '/about'
    })
    </script>
    
  3. 使用 ElementPlus el-tabs 标签组件,Scrollbar 组件替换浏览器原生滚动条:

    <template><!-- Tab Bar --><div class="tab-bar-container"><div class="tab-bar-box"><el-scrollbar><el-tabstab-position="top"type="card"closable><el-tab-panev-for="(item, index) in tabs":key="index":name="item.name"><template #label><span class="tab-title"><svg-icon :name="item.icon" /><span>{{ item.label }}</span></span></template></el-tab-pane></el-tabs></el-scrollbar></div><div class="more-button"><el-dropdown trigger="click"><span><svg-icon name="More" /></span><template #dropdown><el-dropdown-menu><el-dropdown-item>关闭</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="scss">
    .tab-bar-container {display: flex;align-items: center;gap: 8px;border-bottom: 1px solid var(--el-border-color-light);.tab-bar-box {display: flex;flex-grow: 1;margin-left: 8px;width: calc(100% - 60px);.tab-title{display: flex;align-items: center;gap: 8px;}}.more-button {display: flex;align-items: center;justify-content: center;width: var(--os-layout-tab-height);height: var(--os-layout-tab-height);border-left: 1px solid var(--el-border-color-light);}
    }:deep(.el-tabs) {.el-tabs__header {height: var(--os-layout-tab-height);padding: 0;margin: 0;border-bottom: none;.el-tabs__nav-wrap {.el-tabs__nav-scroll {.el-tabs__nav {border: none;.el-tabs__item {height: calc(var(--os-layout-tab-height) - 2px);line-height: calc(var(--os-layout-tab-height) - 2px);border: none;position: relative; // 确保父元素是相对定位的&::before {content: '';position: absolute;bottom: 0;width: 100%;height: 2px;background-color: transparent;}&.is-active {color: var(--el-color-primary);fill: var(--el-color-primary);&::before {background-color: var(--el-color-primary); // 改变背景色以显示下划线}}}}}}}
    }
    </style>
    

封装 Main 内容区组件

  1. 创建 src/layouts/components/Main/index.vue

    <script setup lang="ts"></script><template><div>Main</div>
    </template><style scoped lang="scss"></style>
    
  2. 后续补充内容…

封装 Footer 底部组件

  1. 创建 src/layouts/components/Footer/index.vue

  2. 通过import.meta.env获取.env文件中定义的环境变量

    <script setup lang="ts">
    const app_title = import.meta.env.VITE_APP_TITLE
    </script>
    
  3. 添加内容:

    <template><div class="footer-container"><!-- 左侧:公司名称或标志 --><div class="flex-content"><svg-icon name="logo" /><span class="logo-title">{{ app_title }}</span></div><!-- 中间:导航链接 --><div class="flex-content"><a href="about">关于我们</a><a href="#contact">联系我们</a><a href="#privacy-policy">隐私政策</a><a href="#terms-of-service">服务条款</a></div><!-- 右侧:版权信息 --><div class="text-right">&copy; 2024 Octopus. 保留所有权利.</div></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="postcss">
    .footer-container{@apply flex items-center w-full;@apply select-none text-xs;height: var(--os-layout-footer-height);@apply justify-center lg:justify-between;.flex-content{@apply items-center gap-2;@apply flex justify-center gap-1 text-gray-400;@apply hidden lg:flex;.logo-title {@apply font-bold subpixel-antialiased text-sm;@apply bg-clip-text text-transparent bg-gradient-to-r from-pink-500 to-violet-500;}}
    }
    </style>
    

封装 Theme 主题组件

  1. 创建 src/stores/modules/theme/types.ts 定义主题类型:

    export type LayoutMode = 'classic' | 'horizontal' | 'responsive'
    // 主题配置
    export interface ThemeConfig {showThemeConfig: boolean,darkThemeEnabled: boolean,grayThemeEnabled: boolean,layoutMode: LayoutMode,themePrimaryColor: string,predefineColors: string[]
    }
    
  2. 创建 src/stores/modules/theme/index.ts 仓库存储主题状态:

    import { defineStore } from 'pinia'
    import { reactive, watch } from 'vue'
    import { ThemeConfig } from './types'
    import { ElMessage } from 'element-plus'
    import { getDarkColor, getLightColor } from '@/utils/Color'// theme store
    export const useThemeStore = defineStore('theme',() => {const themeConfig = reactive<ThemeConfig>({showThemeConfig: false,darkThemeEnabled: false,grayThemeEnabled: false,layoutMode: 'classic',themePrimaryColor: '#409eff',predefineColors: ['#409eff']})// 切换显示状态的方法const toggleThemeConfig = () => {themeConfig.showThemeConfig = !themeConfig.showThemeConfig}// 黑暗主题切换watch(() => themeConfig.darkThemeEnabled, () => {const html = document.documentElement as HTMLElementif (themeConfig.darkThemeEnabled) {html.setAttribute('class', 'dark')} else {html.removeAttribute('class')}changeThemeColor(themeConfig.themePrimaryColor)})watch(() => themeConfig.grayThemeEnabled,() => {if (themeConfig.grayThemeEnabled) {document.documentElement.dataset.theme = 'gray'} else {document.documentElement.dataset.theme = ''}})// 添加预定义颜色function addPredefineColor(color:string) {console.log('color', color)const predefineColors = themeConfig.predefineColors// 查找元素的索引const index = predefineColors.indexOf(color)if (index !== -1) {// 使用 splice 方法删除该元素predefineColors.splice(index, 1)}if (themeConfig.predefineColors.length === 10) {themeConfig.predefineColors.pop() // 删除队列中的第一个元素}themeConfig.predefineColors.unshift(color)}// 修改主题颜色const changeThemeColor = (color:string ) => {if (!color) {color = '#409eff'ElMessage({ type: 'success', message: '主题颜色已重置' })}addPredefineColor(color)// 计算主题颜色变化document.documentElement.style.setProperty('--el-color-primary', color)document.documentElement.style.setProperty('--el-color-primary-dark-2',themeConfig.darkThemeEnabled ? `${getLightColor(color, 0.2)}` : `${getDarkColor(color, 0.3)}`)for (let i = 1; i <= 9; i++) {const primaryColor = themeConfig.darkThemeEnabled ? `${getDarkColor(color, i / 10)}` : `${getLightColor(color, i / 10)}`document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, primaryColor)}}return {themeConfig,toggleThemeConfig,changeThemeColor}},{persist: true})
    
  3. 创建 src/layouts/components/Theme/index.vue 主题组件并引入主题仓库:

    <script setup lang="ts">
    import { useThemeStore } from '@/stores/modules/theme'
    import { onMounted } from 'vue'const { themeConfig, changeThemeColor } = useThemeStore()onMounted(() => {// 在组件挂载到 DOM 后更新主题颜色changeThemeColor(themeConfig.themePrimaryColor)
    })
    </script>
    
  4. 使用 el-drawer 抽屉组件进行主题布局:

    <template><div><el-drawer v-model="themeConfig.showThemeConfig" size="300"><template #header="{ titleId }"><span :id="titleId" class="theme-header"> 主题配置 </span></template><el-scrollbar><div class="mr-4"><el-divider>布局样式</el-divider><div class="layout-box"><el-tooltip effect="dark" content="经典布局" placement="top" :show-after="200"><div:class="['layout-item layout-classic', { 'is-active': themeConfig.layoutMode == 'classic' }]"@click="themeConfig.layoutMode='classic'"><div class="layout-dark"></div><div class="layout-container"><div class="layout-light"></div><div class="layout-content"></div></div><svg-icon class="select-layout" name="About" v-if="themeConfig.layoutMode == 'classic'" /></div></el-tooltip><el-tooltipeffect="dark"content="横向布局"placement="top":show-after="200"><div:class="['layout-item layout-transverse', { 'is-active': themeConfig.layoutMode == 'horizontal' }]"@click="themeConfig.layoutMode='horizontal'"><div class="layout-dark"></div><div class="layout-content"></div><svg-icon class="select-layout" name="About" v-if=" themeConfig.layoutMode == 'horizontal'" /></div></el-tooltip></div><el-divider>主题风格</el-divider><div class="switch-container"><div class="switch-box"><div class="switch-title"><span>主题颜色</span><el-tooltip content="主题颜色" placement="top"><svg-icon class="size-4" name="About"></svg-icon></el-tooltip></div><el-color-pickercolor-format="hex"v-model="themeConfig.themePrimaryColor":predefine="themeConfig.predefineColors"@change="changeThemeColor"/></div><div class="switch-box"><div class="switch-title"><span>暗黑主题</span><el-tooltip content="暗黑主题" placement="top"><svg-icon class="size-4" name="About"></svg-icon></el-tooltip></div><el-switch v-model="themeConfig.darkThemeEnabled" /></div><div class="switch-box"><div class="switch-title"><span>灰色模式</span><el-tooltip content="灰色模式" placement="top"><svg-icon class="size-4" name="About"></svg-icon></el-tooltip></div><el-switch v-model="themeConfig.grayThemeEnabled" /></div></div><el-divider>界面设置</el-divider><div class="switch-container"><div class="switch-box"><div class="switch-title"><span>theme</span></div><el-switch inline-prompt /></div></div></div></el-scrollbar></el-drawer></div>
    </template>
    
  5. 为组件添加样式:

    <style scoped lang="postcss">
    .theme-header {@apply text-base font-bold flex items-center;
    }.switch-container {@apply flex-grow space-y-2;
    }.switch-box {@apply flex justify-between items-center w-full;
    }.switch-title {@apply flex gap-2 items-center;
    }:deep(.el-drawer__header) {@apply px-5 py-0 h-12 border-b-2 border-solid m-0;color: var(--el-text-color-regular);border-color: var(--el-border-color-light);
    }:deep(.el-drawer__title) {font-size: 20px;
    }:deep(.el-drawer__body) {@apply py-0 pr-0;
    }.layout-box {position: relative;display: flex;flex-wrap: wrap;justify-content: space-between;padding: 15px 15px 0;.layout-item {position: relative;box-sizing: border-box;width: 100px;height: 70px;padding: 6px;cursor: pointer;border-radius: 5px;box-shadow: 0 0 5px 1px var(--el-border-color-dark);transition: all 0.2s;.layout-dark {background-color: var(--el-color-primary);border-radius: 3px;}.layout-light {background-color: var(--el-color-primary-light-5);border-radius: 3px;}.layout-content {background-color: var(--el-color-primary-light-8);border: 1px dashed var(--el-color-primary);border-radius: 3px;}.select-layout {position: absolute;right: 10px;bottom: 10px;fill: var(--el-color-primary);transition: all 0.2s;}&:hover {box-shadow: 0 0 5px 1px var(--el-text-color-secondary);}}.is-active {box-shadow: 0 0 0 2px var(--el-color-primary) !important;}.layout-classic {display: flex;justify-content: space-between;margin-bottom: 20px;.layout-dark {width: 20%;}.layout-container {display: flex;flex-direction: column;justify-content: space-between;width: 72%;.layout-light {height: 20%;}.layout-content {height: 67%;}}}.layout-transverse {display: flex;flex-direction: column;justify-content: space-between;margin-bottom: 15px;.layout-dark {height: 20%;}.layout-content {height: 67%;}}
    }
    </style>
    

经典布局

  1. 创建经典页面布局组件:src/layouts/LayoutClassic/index.vue

  2. 导入布局组件:

    <script setup lang="ts">
    import Footer from '@/layouts/components/Footer/index.vue'; // 引入页脚组件
    import Menu from '@/layouts/components/Menu/index.vue'; // 引入菜单组件
    import Logo from '@/layouts/components/Logo/index.vue'; // 引入Logo组件
    import Main from '@/layouts/components/Main/index.vue'; // 引入主要内容组件
    import TabBar from '@/layouts/components/TabBar/index.vue'; // 引入标签栏组件
    import Breadcrumb from '@/layouts/components/Breadcrumb/index.vue'; // 引入面包屑导航组件import { useThemeStore } from '@/stores/modules/theme' // 引入主题仓库
    const { toggleThemeConfig } = useThemeStore()
    
  3. 使用 ElementPlus 提供的 Container 布局容器快速搭建页面的基本结构:

  4. 在组件中使用布局组件划分出页面结构:侧边菜单栏、顶部、Tab 标签栏、主体和底部:

    <el-container>:外层容器。 当子元素中包含 <el-header><el-footer> 时,全部子元素会垂直上下排列, 否则会水平左右排列。

    <el-header>:顶栏容器。

    <el-aside>:侧边栏容器。

    <el-main>:主要区域容器。

    <el-footer>:底栏容器。

    <template><div class="layout-container"><el-container><!-- 左侧边栏 --><el-aside><!-- Logo 组件 --><Logo class="os-logo"/><!-- 菜单组件 --><Menu class="menu-classic" /></el-aside><el-container><!-- 页面顶部区域 --><el-header><!-- 头部内容区域 --><div class="header-content"><!-- 折叠按钮 --><svg-icon class="fold-expand-button" name="Fold" /><!-- 面包屑导航 --><Breadcrumb /></div><!-- 头部菜单区域 --><div class="header-menu"><!-- 语言切换下拉菜单 --><el-dropdown :hide-on-click="false"><svg-icon name="Earth" /><template #dropdown><el-dropdown-menu><el-dropdown-item>简体中文</el-dropdown-item></el-dropdown-menu></template></el-dropdown><!-- 搜索按钮 --><svg-icon class="cursor-pointer" name="Search" /><!-- 主题配置按钮 --><el-tooltip content="主题配置" placement="bottom"><svg-icon class="cursor-pointer" name="Theme" @click="toggleThemeConfig" /></el-tooltip><!-- 锁屏按钮 --><el-tooltip content="锁屏" placement="bottom"><svg-icon class="cursor-pointer" name="Lock" /></el-tooltip><!-- 全屏按钮 --><el-tooltip content="全屏" placement="bottom"><svg-icon class="cursor-pointer" name="FullScreen" /></el-tooltip><!-- 用户信息下拉菜单 --><el-dropdown><div class="flex items-center gap-1"><el-tag type="primary">Admin</el-tag><el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" /></div><template #dropdown><el-dropdown-menu><el-dropdown-item command="profile"><template #default><div class="flex items-center gap-1"><svg-icon name="User" /><span>个人中心</span></div></template></el-dropdown-item><el-dropdown-item command="logout"><template #default><div class="flex items-center gap-1"><svg-icon name="Logout" /><span>退出登录</span></div></template></el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></el-header><!-- 标签栏 --><tab-bar class="tab-container" /><!-- 主内容区域 --><el-main><Main /></el-main><!-- 底部页脚 --><el-footer><Footer /></el-footer></el-container></el-container></div>
    </template>
    
  5. 为组件添加样式:

    <style scoped lang="postcss">
    .layout-container {@apply w-screen h-screen;.el-aside {@apply h-full;@apply border-r border-solid overflow-hidden;border-color: var(--el-border-color-light);width: var(--os-layout-aside-width);.os-logo {@apply overflow-hidden pl-2;}.menu-classic {height: calc(100vh - var(--os-layout-logo-height));}}.el-container {@apply h-full w-full;.tab-container {height: var(--os-layout-tab-height);}.el-header {@apply flex items-center justify-between;@apply border-b border-solid overflow-hidden;border-color: var(--el-border-color-light);height: var(--os-layout-header-height);.header-content {@apply flex items-center gap-5;.fold-expand-button {@apply cursor-pointer;@apply size-6;}}.header-menu {@apply flex items-center justify-between gap-3;}}.el-main {@apply h-full p-3;background-color: var(--el-bg-color-page);}.el-footer {height: var(--os-layout-footer-height);}}
    }
    </style>
    

水平布局

  1. 创建经典页面布局组件:src/layouts/LayoutClassic/index.vue

  2. 导入布局组件:

    <script setup lang="ts">
    import Footer from '@/layouts/components/Footer/index.vue'; // 引入页脚组件
    import Menu from '@/layouts/components/Menu/index.vue'; // 引入菜单组件
    import Logo from '@/layouts/components/Logo/index.vue'; // 引入Logo组件
    import Main from '@/layouts/components/Main/index.vue'; // 引入主要内容组件
    import TabBar from '@/layouts/components/TabBar/index.vue'; // 引入标签栏组件import { useThemeStore } from '@/stores/modules/theme' // 引入主题仓库
    const { toggleThemeConfig } = useThemeStore()
    </script>
    
  3. 在组件中使用 Element UI 的布局组件划分出页面结构:顶部、Tab 标签栏、主体和底部:

    <template><div class="layout-container"><el-container><el-container><el-header><div class="flex"><Logo class="os-logo" /><Menu mode="horizontal" class="menu-horizontal " /></div><div class="header-menu"><!-- 语言转换 --><el-dropdown :hide-on-click="false"><svg-icon name="Earth" /><template #dropdown><el-dropdown-menu><el-dropdown-item>简体中文</el-dropdown-item></el-dropdown-menu></template></el-dropdown><!-- 搜索按钮 --><svg-icon class="cursor-pointer" name="Search" /><!-- 皮肤按钮 --><el-tooltip content="主题配置" placement="bottom"><svg-icon class="cursor-pointer" name="Theme" @click="toggleThemeConfig"/></el-tooltip><!-- 锁屏按钮 --><el-tooltip content="锁屏" placement="bottom"><svg-icon class="cursor-pointer" name="Lock" /></el-tooltip><!-- 全屏按钮 --><el-tooltip content="全屏" placement="bottom"><svg-icon class="cursor-pointer" name="FullScreen" /></el-tooltip><!-- 用户信息 --><el-dropdown><div class="flex items-center gap-1"><el-tag type="primary">Admin</el-tag><el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" /></div><template #dropdown><el-dropdown-menu><el-dropdown-item command="profile"><template #default><div class="flex items-center gap-1"><svg-icon name="User" /><span>个人中心</span></div></template></el-dropdown-item><el-dropdown-item command="logout"><template #default><div class="flex items-center gap-1"><svg-icon name="Logout" /><span>退出登录</span></div></template></el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></el-header><tab-bar class="tab-container" /><el-main><Main /></el-main><el-footer><Footer /></el-footer></el-container></el-container></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="postcss">
    .layout-container {@apply w-screen h-screen;.el-aside {@apply bg-amber-300 h-full;width: var(--os-layout-aside-width);}.el-container {@apply h-full w-full;.tab-container {height: var(--os-layout-tab-height);}.el-header {@apply w-full pl-2 pr-2 flex justify-between;height: var(--os-layout-header-height);@apply border-b border-solid overflow-hidden;border-color: var(--el-border-color-light);.menu-horizontal{width: calc(100vw - var(--os-layout-aside-width) - var(--os-layout-header-menu-width));}.header-menu{@apply flex items-center justify-between gap-3;}}.el-main {@apply h-full p-3;background-color:var(--el-bg-color-page);}.el-footer {height: var(--os-layout-footer-height);}}
    }
    </style>
    

响应式布局

  1. 创建src/layouts/LayoutResponsive/index.vue响应式布局组件

  2. 添加公共组件:

    <script setup lang="ts">
    import Logo from '@/layouts/components/Logo/index.vue'
    import Main from '@/layouts/components/Main/index.vue'
    import Menu from '@/layouts/components/Menu/index.vue'
    import { ref } from 'vue'import { useThemeStore } from '@/stores/modules/theme'
    const { themeConfig } = useThemeStore()const navDrawer = ref(false)
    const menuDrawer = ref(false)
    const translateShow = ref(false)
    </script>
    
  3. 页面布局:

    <template><div class="layout-responsive"><el-container><el-header class="flex items-center justify-between"><div class="h-full flex items-center gap-2"><svg-icon width="30px" height="30px" name="menu" @click="menuDrawer = !menuDrawer" /><Logo /></div><div class="header-menu"><!-- 搜索按钮 --><svg-icon width="28px" height="28px" class="cursor-pointer" name="Search" /><!-- 用户信息 --><el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"@click="navDrawer = !navDrawer" /><!-- 导航信息 -->  <el-drawer v-model="navDrawer" size="100%"><template #header><Logo /></template><div class="nav-container "><a href="#">个人中心</a><el-divider /><div><span class="flex items-center justify-between" @click="translateShow = !translateShow">翻译<svg-icon name="Earth"></svg-icon></span><!-- 语言列表 --><transition name="fade"><div v-show="translateShow" id="language-list" class="language-list mt-2"><ul><li class="p-2">英语</li><li class="p-2">中文</li><li class="p-2">西班牙语</li></ul></div></transition></div><el-divider /><div class="nav-theme-switch"><span>暗黑主题</span><el-switch v-model="themeConfig.darkThemeEnabled" size="large" /></div><el-divider /><span>退出登录</span></div></el-drawer></div></el-header><el-main><el-backtop target=".el-main" /><Main /></el-main></el-container><!-- 菜单组件 --><el-drawerv-model="menuDrawer"direction="ltr"size="320px"><Menu /></el-drawer></div>
    </template>
    
  4. 添加样式:

    <style scoped lang="postcss">
    .layout-responsive {@apply w-screen h-screen;.el-container {@apply h-full w-full;.el-header {@apply w-full flex pl-2;height: var(--os-layout-header-height);@apply border-b border-solid overflow-hidden;border-color: var(--el-border-color-light);.header-menu {@apply flex items-center justify-between gap-3;}}.tab-container {background-color: var(--el-bg-color);}.el-main {@apply h-full;background-color: var(--el-bg-color-page);}}
    }:deep(.el-drawer__header) {@apply px-3 py-0 h-14 border-solid m-2;color: var(--el-text-color-regular);border-color: var(--el-border-color-light);
    }:deep(.el-drawer__title) {font-size: 20px;
    }:deep(.el-drawer__body) {@apply py-0 px-8;
    }:deep(.el-drawer__close-btn) {@apply text-3xl;
    }.nav-container {margin: 0 auto;padding: 24px 0 96px;max-width: 18rem;
    }.nav-theme-switch {@apply flex items-center justify-between rounded-md;
    }/* 添加动画效果 */
    .fade-enter-active {transition: opacity 0.5s ease;
    }.fade-leave-active {transition: opacity 0.2s ease;
    }.fade-enter-from, .fade-leave-to {opacity: 0;
    }.logo-title {@apply text-lg font-bold subpixel-antialiased;@apply bg-clip-text text-transparent bg-gradient-to-r from-pink-500 to-violet-500;
    }
    </style>
    

搭建 Layout 布局组件

  1. 创建 Layout 布局组件 src/layouts/index.vue

  2. 导入经典布局组件 LayoutClassic 和水平布局组件 LayoutHorizontal,创建一个 layoutMode 对象来将布局模式字符串映射到相应的组件,使用 computed 函数根据 mode 动态选择布局模式。

    <script setup lang="ts">
    import { type Component, computed, onMounted, onUnmounted, ref, watch } from 'vue'
    import LayoutClassic from '@/layouts/LayoutClassic/index.vue'
    import LayoutHorizontal from '@/layouts/LayoutHorizontal/index.vue'
    import LayoutResponsive from '@/layouts/LayoutResponsive/index.vue'
    import Theme from '@/layouts/components/Theme/index.vue'import { useThemeStore } from '@/stores/modules/theme'
    const { themeConfig } = useThemeStore()// 定义布局模式与对应的组件类型
    const layoutMode: Record<string, Component> = {classic: LayoutClassic,   // 经典布局horizontal: LayoutHorizontal,  // 横向布局responsive: LayoutResponsive  // 响应式布局
    }// 布局模式
    const layMode = ref(themeConfig.layoutMode)// 监听主题配置模式
    watch(() => themeConfig.layoutMode, (newMode) => {layMode.value = newMode
    })// 计算属性,根据具体逻辑返回所选布局的组件
    const mode = computed(() => layoutMode[layMode.value])// 响应式布局,切换布局模式
    const updateMode = () => {if (window.innerWidth <= 768) {layMode.value = 'responsive'} else {layMode.value = themeConfig.layoutMode}
    }onMounted(() => {// 初始更新updateMode()window.addEventListener('resize', updateMode)
    })onUnmounted(() => {window.removeEventListener('resize', updateMode)
    })
    </script><template><!-- 根据 mode 的值渲染不同的布局样式 --><component :is="mode" /><Theme />
    </template><style scoped lang="postcss">
    </style>
    

添加 Layout 路由配置

  1. src/App.vue 中添加代码,当访问路由路径时,Vue Router 会根据路由配置将对应的组件渲染到 <router-view> 中,实现单页应用的页面切换效果:

    <template><router-view />
    </template>
    
  2. src/router/index.ts 中添加路由:

    const router = createRouter({routes: [{path: '/',name: 'layout',component: () => import('@/layouts/index.vue')}]
    })
    

启动项目

  1. 终端执行命令启动项目:

    pnpm run dev
    
  2. 浏览器访问:http://localhost:8080/,默认为经典布局样式:

    image-20240805095808149

  3. src/layouts/index.vue 中切换为水平布局样式,查看页面:

    const mode = computed(() => layoutMode['horizontal'])
    

    image-20240805095901012

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/426052.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity实战案例全解析:PVZ 植物放置分析

前篇&#xff1a;Unity实战案例全解析&#xff1a;PVZ 植物卡片状态分析-CSDN博客 植物应该如何从卡牌状态转为实物&#xff1f; 其实就只需要考虑两个步骤加一个后续处理&#xff1a; 1.点击卡牌后就实例化 需要一个植物状态枚举&#xff0c;因为卡牌分为拿在手上和种植下…

道路裂缝,坑洼,病害数据集-包括无人机视角,摩托车视角,车辆视角覆盖道路

道路裂缝&#xff0c;坑洼&#xff0c;病害数据集 包括无人机视角&#xff0c;摩托车视角&#xff0c;车辆视角 覆盖道路所有问题 一共有八类16000张 1到7依次为: [横向裂缝, 纵向裂缝, 块状裂缝, 龟裂, 坑槽, 修补网状裂缝, 修补裂缝, 修补坑槽] 道路病害&#xff08;如裂缝、…

MQ(RabbitMQ)笔记

初识MQ 同步调用优缺点 异步调用优缺点 总结&#xff1a; 时效性要求高&#xff0c;需要立刻得到结果进行处理--->同步调用 对调用结果不关心&#xff0c;对性能要求高&#xff0c;响应时间短--->异步调用

人工智能和大模型的简介

文章目录 前言一、大模型简介二、大模型主要功能1、自然语言理解和生成2、文本总结和翻译3、文本分类和信息检索4、多模态处理三、大模型的技术特性1、深度学习架构2、大规模预训练3、自适应能力前言 随着技术的进步,人工智能(Artificial Intelligence, AI)和机器学习(Mac…

NPM如何切换淘宝镜像进行加速

什么是淘宝镜像NPM&#xff1f; 淘宝镜像NPM和官方NPM的主要区别在于服务器的地理位置和网络访问速度。淘宝镜像NPM是由淘宝团队维护的一个npm镜像源&#xff0c;主要服务于中国大陆用户&#xff0c;提供了一个国内的npm镜像源&#xff0c;地址为 https://registry.npmmirror.…

论文阅读 - SELF-REFINE: Iterative Refinement with Self-Feedback

https://arxiv.org/pdf/2303.17651 目录 Abstract Introduction 2 Iterative Refinement with SELF-REFINE Evaluation 3.1 Instantiating SELF-REFINE 3.2 Metrics 3.3 Results Abstract 与人类一样&#xff0c;大型语言模型&#xff08;LLMs&#xff09;并非总能在首次…

【有啥问啥】深入浅出马尔可夫链蒙特卡罗(Markov Chain Monte Carlo, MCMC)算法

深入浅出马尔可夫链蒙特卡罗&#xff08;Markov Chain Monte Carlo, MCMC&#xff09;算法 0. 引言 Markov Chain Monte Carlo&#xff08;MCMC&#xff09;是一类用于从复杂分布中采样的强大算法&#xff0c;特别是在难以直接计算分布的情况下。它广泛应用于统计学、机器学习…

【python设计模式2】创建型模式1

目录 简单工厂模式 工厂方法模式 简单工厂模式 简单工厂模式不是23中设计模式中的&#xff0c;但是必须要知道。简单工厂模式不直接向客户端暴露对象创建的细节&#xff0c;而是通过一个工厂类来负责创建产品类的实例。简单工程模式的角色有&#xff1a;工厂角色、抽象产品角…

Redis——常用数据类型string

目录 常用数据结构&#xff08;类型&#xff09;Redis单线程模型Reids为啥效率这么高&#xff1f;速度这么快&#xff1f;&#xff08;参照于其他数据库&#xff09; stringsetgetMSET 和 MGETSETNX&#xff0c;SETEX&#xff0c;PSETEXincr&#xff0c;incrby&#xff0c;decr…

go多线程

1、简单使用&#xff08;这个执行完成&#xff0c;如果进程执行比较久&#xff0c;这里不会等待它们结束&#xff09; package mainimport "time"func main() {go func() {println("Hello, World!")}()time.Sleep(1 * time.Second) }2、wg.Add(数量)使用&…

STM32 定时器 输入捕获

定时器输入捕获 1 工作原理1.1 单个通道的工作原理 2 输入滤波2.1 输入滤波原理 3 边沿检测3.1 边沿检测3.2 信号选择 4 分频5 通道使能 1 工作原理 1.1 单个通道的工作原理 2 输入滤波 2.1 输入滤波原理 fck_INT&#xff1a;内部时钟频率&#xff0c;当PCLKx_Pre为1时&…

prometheus 集成 grafana 保姆级别安装部署

前言 本文 grafana 展示效果只需要 prometheus node_exporter grafana 其他的选择安装 环境和版本号 系统: CentOS 7.9 prometheus: 2.54.1 pushgateway: 1.9.0 node_exporter: 1.8.2 alertmanager: 0.27.0 grafana:11.2.0 官网:https://prometheus.io/ 下载地址:h…

软件测试 | APP测试 —— Appium 的环境搭建及工具安装教程

大家应该都有同一种感觉&#xff0c;学习appium最大的难处之一在于环境的安装&#xff0c;安装流程比较繁琐&#xff0c;安装的工具和步骤也较多&#xff0c;以下是基于Windows系统下的Android手机端的安装流程。就像我们在用Selenium进行web自动化测试的时候一样&#xff0c;我…

Gin渲染

HTML渲染 【示例1】 首先定义一个存放模板文件的 templates文件夹&#xff0c;然后在其内部按照业务分别定义一个 posts 文件夹和一个 users 文件夹。 posts/index.tmpl {{define "posts/index.tmpl"}} <!DOCTYPE html> <html lang"en">&…

计算机毕业设计 视频点播网站 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

day22JS-npm中的部分插件使用方法

1. 静态资源目录 静态资源目录就是访问服务器的某些路劲时候&#xff0c;服务器可以吐出一个写好的指定页面。 实现思路&#xff1a; 1、先判断要找的路径是否是文件&#xff0c;如果是文件&#xff0c;就加载发给对方。 2、如果是文件夹&#xff0c;找到这个文件夹所在路径中…

Spring Boot基础

项目创建 项目启动 请求响应 RestController 1.返回值处理 RestController&#xff1a;这个注解结合了Controller和ResponseBody的功能。它默认将所有处理请求的方法的返回值直接作为响应体内容返回&#xff0c;主要用于构建RESTful API。返回的数据格式通常是JSON或XML&…

Linux:软件包管理器 yum和编辑器-vim使用

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《Linux&#xff1a;软件包管理器 yum和编辑器-vim使用》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点…

整流电路的有源逆变工作状态

目录 1. 逆变的概念 2. 有源逆变的条件 3. 电流电路的概念 4. 产生逆变的条件 5. 三相桥式全控整流电路的有源逆变工作状态 6. 逆变角的概念 7. 逆变失败的原因 8. 最小逆变角的限制 整流电路的有源逆变状态是指通过控制整流器&#xff0c;使其将直流电源的能量反向送回…

[乱码]确保命令行窗口与主流集成开发环境(IDE)统一采用UTF-8编码,以规避乱码问题

文章目录 一、前言二、命令行窗口修改编码为UTF-8三、Visual Studio 2022修改编码为UTF-8四、Eclipse修改编码为UTF-8五、DevCPP修改编码为UTF-8六、Sublime Text修改编码为UTF-8七、PyCharm、IDEA、VS Code及Python自带解释器修改编码为UTF-8 一、前言 在学习的征途中&#x…