Vue3+Vite+Ts 项目实战 04 搭建 Layout 布局

2024-08-23 01:08

本文主要是介绍Vue3+Vite+Ts 项目实战 04 搭建 Layout 布局,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Layout 布局容器

<!-- src\layout\AppLayout.vue -->
<template><el-container><el-aside width="200px">Aside</el-aside><el-container><el-header>Header</el-header><el-main><!-- 子路由出口 --><router-view /></el-main></el-container></el-container>
</template><script setup lang="ts"></script><style scoped lang="scss">
.el-container {height: 100vh;
}
.el-header {background-color: #B3C0D1;
}
.el-aside {width: auto;background-color: #304156;
}
.el-main {background-color: #E9EEF3;
}
</style>
// src\styles\common.scss
* {margin: 0;padding: 0;
}
// src\router\index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import AppLayout from '@/layout/AppLayout.vue'const routes:RouteRecordRaw[] = [{path: '/',component: AppLayout,children: [{path: '/',name: 'home',component: () => import('@/views/home/index.vue')}]},{path: '/login',name: 'login',component: () => import('@/views/login/index.vue')}
]const router = createRouter({// history: createWebHashHistory(), // hash 路由模式history: createWebHistory(), // history 路由模式routes // 路由规则
})export default router

配置页面路由导航

初始化路由目录

创建其他几个页面文件(后面可能还会增加):

└─ product # 商品相关├─ attr # 商品规格│   └─ index.vue├─ category # 商品分类│   └─ index.vue└─ list # 商品列表└─ index.vue

配置路由:

// src\router\modules\products.ts
import { RouteRecordRaw, RouterView } from 'vue-router'const routes:RouteRecordRaw = {path: 'product',component: RouterView,children: [{path: 'list',name: 'product_list',component: () => import('@/views/product/list/index.vue')},{path: 'category',name: 'product_category',component: () => import('@/views/product/category/index.vue')},{path: 'attr',name: 'product_attr',component: () => import('@/views/product/attr/index.vue')},{path: 'reply',name: 'product_reply',component: () => import('@/views/product/reply/index.vue')}]
}export default routes
// src\router\index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import AppLayout from '@/layout/AppLayout.vue'
import productRoutes from './modules/product'const routes:RouteRecordRaw[] = [{path: '/',component: AppLayout,children: [{path: '/',name: 'home',component: () => import('@/views/home/index.vue')},productRoutes]},{path: '/login',name: 'login',component: () => import('@/views/login/index.vue')}
]const router = createRouter({// history: createWebHashHistory(), // hash 路由模式history: createWebHistory(), // history 路由模式routes // 路由规则
})export default router

菜单导航

暂时静态编写几个菜单内容:

<!-- src\layout\components\AppMenu.vue -->
<template><el-menuactive-text-color="#ffd04b"background-color="#304156"class="el-menu-vertical-demo"default-active="2"text-color="#fff"router><el-menu-item index="/"><!-- <Menu> 首字母要大写,否则会和浏览器原生的 <menu> 冲突 --><el-icon><Menu /></el-icon><span>首页</span></el-menu-item><el-sub-menu index="1"><template #title><el-icon><location /></el-icon><span>商品</span></template><el-menu-item index="/product/list"><el-icon><Menu /></el-icon><span>商品列表</span></el-menu-item><el-menu-item index="/product/category"><el-icon><Menu /></el-icon><span>商品分类</span></el-menu-item><el-menu-item index="/product/attr"><el-icon><Menu /></el-icon><span>商品规格</span></el-menu-item></el-sub-menu></el-menu>
</template><script setup lang="ts"></script><style scoped></style>
<!-- src\layout\AppLayout.vue -->
<template><el-container><el-aside width="200px"><AppMenu /></el-aside><el-container><el-header>Header</el-header><el-main><!-- 子路由出口 --><router-view /></el-main></el-container></el-container>
</template><script setup lang="ts">
import AppMenu from './AppMenu/index.vue'
</script><style scoped lang="scss">...</style>

切换侧边栏展开收起

存储侧边栏展开状态:

// src\store\index.ts
import { defineStore } from 'pinia'const useStore = defineStore('main', {state: () => ({count: 0,isCollapse: false}),getters: {doubleCount(state) {return state.count * 2}},actions: {increment() {this.count++}}
})export default useStore

创建 Header 布局组件,编写侧边栏控制按钮:

<!-- src\layout\AppHeader\index.vue -->
<template><ToggleSidebar /><!-- 面包屑 -->
</template><script setup lang="ts">
import ToggleSidebar from './ToggleSidebar.vue'
</script><style scoped lang="scss" >
i {font-size: 19px;cursor: pointer;
}
</style>
<!-- src\layout\AppHeader\ToggleSidebar.vue -->
<template><el-icon><component:is="store.isCollapse ? 'expand' : 'fold'"@click="handleCollapse"/></el-icon>
</template><script setup lang="ts">
import useStore from '@/store'const store = useStore()// 因为没有其他地方可以修改侧边栏状态
// 所以这里直接修改
const handleCollapse = () => {store.isCollapse = !store.isCollapse
}
</script><style scoped></style>

绑定侧边栏状态,加载 Header 组件,修改 el-header 样式:

<!-- src\layout\AppLayout.vue -->
<template><el-container><el-aside width="200px"><AppMenu /></el-aside><el-container><el-header><AppHeader /></el-header><el-main><!-- 子路由出口 --><router-view /></el-main></el-container></el-container>
</template><script setup lang="ts">
import AppMenu from './AppMenu/index.vue'
import AppHeader from './AppHeader/index.vue'
</script><style scoped lang="scss">
.el-container {height: 100vh;
}
.el-header {background-color: #fff;color: #333;display: flex;justify-content: space-between;align-items: center;
}
.el-aside {width: auto;background-color: #304156;
}
.el-main {background-color: #E9EEF3;
}
</style>

面包屑导航

通过路由元信息配置路由标题

// src\router\modules\products.ts
import { RouteRecordRaw, RouterView } from 'vue-router'const routes:RouteRecordRaw = {path: 'product',component: RouterView,meta: {title: '商品'},children: [{path: 'list',name: 'product_list',component: () => import('@/views/product/list/index.vue'),meta: {title: '商品列表'}},{path: 'category',name: 'product_category',component: () => import('@/views/product/category/index.vue'),meta: {title: '商品分类'}},{path: 'attr',name: 'product_attr',component: () => import('@/views/product/attr/index.vue'),meta: {title: '商品规格'}}]
}export default routes
// src\router\index.ts
...const routes:RouteRecordRaw[] = [{path: '/',component: AppLayout,children: [{path: '/',name: 'home',component: () => import('@/views/home/index.vue'),meta: {title: '首页'}},...]},...
]...

面包屑组件

<!-- src\layout\AppHeader\Breadcrumb.vue -->
<template><el-breadcrumb separator-icon="arrow-right"><el-breadcrumb-itemv-for="item in routes":key="item.path">{{ item.meta.title }}</el-breadcrumb-item></el-breadcrumb>
</template><script setup lang="ts">
import { useRouter } from 'vue-router'
import { computed } from 'vue'// 获取路由,类似 Vue2 的 this.$router
const router = useRouter()// 获取当前路由的匹配记录
const routes = computed(() => {return router.currentRoute.value.matched.filter(item => item.meta.title)
})</script><style scoped></style>

加载面包屑组件

<!-- src\layout\AppHeader\index.vue -->
<template><el-space size="large"><ToggleSidebar /><Breadcrumb /></el-space>
</template><script setup lang="ts">
import ToggleSidebar from './ToggleSidebar.vue'
import Breadcrumb from './Breadcrumb.vue'
</script><style scoped lang="scss" >
i {font-size: 19px;cursor: pointer;
}
</style>

配置路由元信息 TypeScript 支持,为了方便将自定义创建的类型声明文件放到 src/types 目录下:

// src\types\vue-router.d.ts
import 'vue-router'declare module 'vue-router' {// eslint-disable-next-line no-unused-varsinterface RouteMeta {title?: string}
}

其他

可以使用 nuxt/vue-meta(next 分支) 设置页面标题。

全屏功能

全屏 API - Web API 接口参考 | MDN

创建全屏按钮组件:

<!-- src\layout\AppHeader\FullScreen.vue -->
<template><el-icon><full-screen @click="toggleFullScreen" /></el-icon>
</template><script setup lang="ts">
const toggleFullScreen = () => {if (!document.fullscreenElement) {document.documentElement.requestFullscreen()} else {if (document.exitFullscreen) {document.exitFullscreen()}}
}
</script><style scoped></style>

加载组件

<!-- src\layout\AppHeader\index.vue -->
<template><el-space size="large"><ToggleSidebar /><Breadcrumb /></el-space><el-space size="large"><FullScreen /></el-space>
</template><script setup lang="ts">
import ToggleSidebar from './ToggleSidebar.vue'
import Breadcrumb from './Breadcrumb.vue'
import FullScreen from './FullScreen.vue'
</script><style scoped lang="scss" >
i {font-size: 19px;cursor: pointer;
}
</style>

页面加载进度条

使用 nprogress 实现页面加载进度条效果。

npm i --save nprogress
# TS 类型补充模块
npm i --save-dev @types/nprogress
// src\router\index.ts
...
import nprogress from 'nprogress'
import 'nprogress/nprogress.css'// 关闭 loading 图标
nprogress.configure({ showSpinner: false })...router.beforeEach(() => {// 开始加载进度条nprogress.start()
})router.afterEach(() => {// 结束加载进度条nprogress.done()
})export default router

注意:Vue Router v4.x 开始不建议在导航守卫中使用 next()来调用下一个导航守卫,转而改用 return 来控制,返回 false 会取消当前导航;返回一个路由地址,则会跳转到这个路由;默认路由会调用。

这篇关于Vue3+Vite+Ts 项目实战 04 搭建 Layout 布局的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1097923

相关文章

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

如何在Spring Boot项目中集成MQTT协议

《如何在SpringBoot项目中集成MQTT协议》本文介绍在SpringBoot中集成MQTT的步骤,包括安装Broker、添加EclipsePaho依赖、配置连接参数、实现消息发布订阅、测试接口... 目录1. 准备工作2. 引入依赖3. 配置MQTT连接4. 创建MQTT配置类5. 实现消息发布与订阅

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)