本文主要是介绍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 布局的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!