开始的想法是通过路由拦截器去实现,但是发现初始化的时候会有冲突,所以后面还是改在框架中去实现。
核心的方法呢就是通过el-tag与路由器去实现。设置watch去监听当前的路由,记得设置deep和immediate,这样才能在初次加载时获取。
<template>
<div >
<el-tag
v-for="tag in tags"
:key="tag.name"
closable
@close="closeTag(tag)"
@click="clickTag(tag)"
:class="{ isChecked: tag.name === checked }"
style="margin-right: 10px; font-size: 14px; cursor: pointer"
>
{{ tag.name }}
</el-tag>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
interface Tag {
name: string
path: string
}
const $route = useRoute()
const $router = useRouter()
const tags = ref<Tag[]>([])
const checked = ref('')
watch(
$route,
(newValue) => {
addTag(newValue)
},
{ immediate: true }
)
function addTag(data: any) {
const findData = tags.value.find((item) => item.name === data.meta.title)
if (!findData) {
tags.value.push({ name: data.meta.title, path: data.path })
}
checked.value = data.meta.title
}
function closeTag(tag: Tag) {
if (tags.value.length === 1) return
const index = tags.value.findIndex((item) => item.name === tag.name)
tags.value.splice(index, 1)
const lastTag = tags.value[tags.value.length - 1]
checked.value = lastTag.name
$router.push(lastTag.path)
}
function clickTag(tag: Tag) {
$router.push(tag.path)
}
</script>
<script lang="ts">
export default {
name: 'Tabs'
}
</script>
<style scoped lang="scss">
.isChecked {
background-color: #09f;
color: #fff;
border: none;
}
</style>