携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
搭建Layout架构 解决方案与实现
全新 vue 能力:组件状态驱动的动态 CSS 值
在 vue3.2 中,除了响应式变化之外,还有一个很重要的更新,那就是组件状态驱动动态 CSS,具体文档可以点击这里查看
既然有了新的特性,那我们就来看一看,使用最新的特性来为 logo-container 指定高度
<template>
<el-avatar :size="logoHeight"></el-avatar>
</template>
<script setup>
const logoHeight = 44
</script>
<style lang="scss" scoped>
.logo-container {
height: v-bind(logoHeight) + 'px';
}
</style>
动态面包屑方案分析
到目前为止,Layout 架构还剩下最后一个功能面包屑导航,这个导航分为两类:
1、静态面包屑
每个页面中写死对应的面包屑菜单,虽然简单但其缺点也很明显:
- 每个页面都得写一遍
- 页面路径结构变化了,需要手动修改
总结来说,就是不好维护,不好扩展
2、动态面包屑
根据当前的 url 自动生成面包屑菜单
无论之后路径发生什么变化,动态面包屑都会正确的进行计算
渲染基本的面包屑组件
创建 components/Breadcrumb/index
<template>
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<!-- 面包屑的最后一项 -->
<el-breadcrumb-item>
<span class="no-redirect">活动详情</span>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped>
.breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
::v-deep .no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
在 layout/components/Navbar 中导入
<template>
<div class="navbar">
<hamburger class="hamburger-container" />
<breadcrumb class="breadcrumb-container" />
</div>
</template>
<style lang="scss" scoped>
.navbar {
.breadcrumb-container {
float: left;
}
}
</style>
动态计算面包屑结构数据
上边我们完成了一个静态的面包屑,下边我们来看看如何实现动态
我们讲静态面包屑分成两个组件
1、el-breadcrumb:包裹性质的容器
2、el-breadcrumb-item:每个单独项
所以说,我们想要动态的菜单,那么就需要根据动态数据渲染 el-breadcrumb-item
那么接下来我们先处理动态数据
这里我们需要用到 route.match 这个属性进行处理(route.match:获取与给定路由地址匹配的标准化的路由记录数组)
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// 生成数组数据
const breadcrumbData = ref([])
const getBreadcrumbData = () => {
breadcrumbData.value = route.matched.filter(
item => item.meta && item.meta.title
)
}
// 监听路由变化时触发
watch(
route,
() => {
getBreadcrumbData()
},
{
immediate: true
}
)
</script>
依据动态数据,渲染面包屑
有了数据,我们就要去渲染面包屑了
<template>
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item
v-for="(item, index) in breadcrumbData"
:key="item.path"
>
<!-- 不可点击项 -->
<span v-if="index === breadcrumbData.length - 1" class="no-redirect">{{
item.meta.title
}}</span>
<!-- 可点击项 -->
<a v-else class="redirect" @click.prevent="onLinkClick(item)">{{
item.meta.title
}}</a>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
// 处理点击事件
const router = useRouter()
const onLinkClick = item => {
console.log(item)
router.push(item.path)
}
// 将来需要进行主题替换,所以这里获取下动态样式
const store = useStore()
const linkHoverColor = ref(store.getters.cssVar.menuBg)
</script>
<style lang="scss" scoped>
.breadcrumb {
.redirect {
color: #666;
font-weight: 600;
}
.redirect:hover {
// 将来需要进行主题替换,所以这里不去写死样式
color: v-bind(linkHoverColor);
}
}
</style>
Vue3 动画处理
Vue3 对动画进行了一些修改(查看文档)
主要的修改只有两个地方
1、过渡类名 v-enter 修改为 v-enter-from
2、过渡类名 v-leave 修改为 v-leave-from
依据这些我们来为面包屑增加一些动画样式
1、在 Breadcrumb/index 中增加 transition-group
<template>
<el-breadcrumb class="breadcrumb" separator="/">
<transition-group name="breadcrumb">
</transition-group>
</el-breadcrumb>
</template>
2、新建 styles/transition 样式文件
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all 0.5s;
}
.breadcrumb-enter-from,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-leave-active {
position: absolute;
}
3、在 styles/index 中导入
@import './transition.scss';