perf: 代码优化 layout/TagsView

This commit is contained in:
pany 2023-06-14 18:15:07 +08:00
parent 46747e7ce2
commit 8706398eb7
2 changed files with 48 additions and 43 deletions

View File

@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { type PropType, computed, ref, watch, nextTick } from "vue" import { type PropType, ref, watch, nextTick } from "vue"
import { RouterLink, useRoute } from "vue-router" import { RouterLink, useRoute } from "vue-router"
import { ElScrollbar } from "element-plus" import { ElScrollbar } from "element-plus"
import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue" import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue"
@ -16,7 +16,9 @@ const props = defineProps({
const route = useRoute() const route = useRoute()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
/** 滚动条组件元素的引用 */
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>() const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
/** 滚动条内容元素的引用 */
const scrollbarContentRef = ref<HTMLDivElement>() const scrollbarContentRef = ref<HTMLDivElement>()
/** 当前滚动条距离左边的距离 */ /** 当前滚动条距离左边的距离 */
@ -92,6 +94,7 @@ const moveTo = () => {
} }
} }
/** 监听路由变化,移动到目标位置 */
watch( watch(
route, route,
() => { () => {
@ -101,10 +104,6 @@ watch(
deep: true deep: true
} }
) )
const showScreenfull = computed(() => {
return settingsStore.showScreenfull
})
</script> </script>
<template> <template>
@ -120,7 +119,7 @@ const showScreenfull = computed(() => {
<el-icon class="arrow right" @click="scrollTo('right')"> <el-icon class="arrow right" @click="scrollTo('right')">
<ArrowRight /> <ArrowRight />
</el-icon> </el-icon>
<Screenfull v-if="showScreenfull" element=".app-main" open-tips="内容区全屏" class="screenfull" /> <Screenfull v-if="settingsStore.showScreenfull" element=".app-main" open-tips="内容区全屏" class="screenfull" />
</div> </div>
</template> </template>
@ -143,7 +142,7 @@ const showScreenfull = computed(() => {
} }
.el-scrollbar { .el-scrollbar {
flex: 1; flex: 1;
// //
white-space: nowrap; white-space: nowrap;
.scrollbar-content { .scrollbar-content {
display: inline-block; display: inline-block;

View File

@ -13,26 +13,35 @@ const route = useRoute()
const tagsViewStore = useTagsViewStore() const tagsViewStore = useTagsViewStore()
const permissionStore = usePermissionStore() const permissionStore = usePermissionStore()
/** 标签页组件元素的引用数组 */
const tagRefs = ref<InstanceType<typeof RouterLink>[]>([]) const tagRefs = ref<InstanceType<typeof RouterLink>[]>([])
/** 右键菜单的状态 */
const visible = ref(false) const visible = ref(false)
/** 右键菜单的 top 位置 */
const top = ref(0) const top = ref(0)
/** 右键菜单的 left 位置 */
const left = ref(0) const left = ref(0)
/** 当前正在右键操作的标签页 */
const selectedTag = ref<TagView>({}) const selectedTag = ref<TagView>({})
/** 固定的标签页 */
let affixTags: TagView[] = [] let affixTags: TagView[] = []
/** 判断标签页是否激活 */
const isActive = (tag: TagView) => { const isActive = (tag: TagView) => {
return tag.path === route.path return tag.path === route.path
} }
/** 判断标签页是否固定 */
const isAffix = (tag: TagView) => { const isAffix = (tag: TagView) => {
return tag.meta?.affix return tag.meta?.affix
} }
/** 筛选出固定标签页 */
const filterAffixTags = (routes: RouteRecordRaw[], basePath = "/") => { const filterAffixTags = (routes: RouteRecordRaw[], basePath = "/") => {
let tags: TagView[] = [] const tags: TagView[] = []
routes.forEach((route) => { routes.forEach((route) => {
if (route.meta?.affix) { if (isAffix(route)) {
const tagPath = path.resolve(basePath, route.path) const tagPath = path.resolve(basePath, route.path)
tags.push({ tags.push({
fullPath: tagPath, fullPath: tagPath,
@ -43,24 +52,22 @@ const filterAffixTags = (routes: RouteRecordRaw[], basePath = "/") => {
} }
if (route.children) { if (route.children) {
const childTags = filterAffixTags(route.children, route.path) const childTags = filterAffixTags(route.children, route.path)
if (childTags.length >= 1) { tags.push(...childTags)
tags = tags.concat(childTags)
}
} }
}) })
return tags return tags
} }
/** 初始化标签页 */
const initTags = () => { const initTags = () => {
affixTags = filterAffixTags(permissionStore.routes) affixTags = filterAffixTags(permissionStore.routes)
for (const tag of affixTags) { for (const tag of affixTags) {
// name // name
if (tag.name) { tag.name && tagsViewStore.addVisitedView(tag)
tagsViewStore.addVisitedView(tag)
}
} }
} }
/** 添加标签页 */
const addTags = () => { const addTags = () => {
if (route.name) { if (route.name) {
tagsViewStore.addVisitedView(route) tagsViewStore.addVisitedView(route)
@ -68,40 +75,43 @@ const addTags = () => {
} }
} }
/** 刷新当前正在右键操作的标签页 */
const refreshSelectedTag = (view: TagView) => { const refreshSelectedTag = (view: TagView) => {
tagsViewStore.delCachedView(view) tagsViewStore.delCachedView(view)
router.replace({ path: "/redirect" + view.path, query: view.query }) router.replace({ path: "/redirect" + view.path, query: view.query })
} }
/** 关闭当前正在右键操作的标签页 */
const closeSelectedTag = (view: TagView) => { const closeSelectedTag = (view: TagView) => {
tagsViewStore.delVisitedView(view) tagsViewStore.delVisitedView(view)
tagsViewStore.delCachedView(view) tagsViewStore.delCachedView(view)
if (isActive(view)) { isActive(view) && toLastView(tagsViewStore.visitedViews, view)
toLastView(tagsViewStore.visitedViews, view)
}
} }
/** 关闭其他标签页 */
const closeOthersTags = () => { const closeOthersTags = () => {
if (selectedTag.value.fullPath !== route.path && selectedTag.value.fullPath !== undefined) { const fullPath = selectedTag.value.fullPath
router.push(selectedTag.value.fullPath) if (fullPath !== route.path && fullPath !== undefined) {
router.push(fullPath)
} }
tagsViewStore.delOthersVisitedViews(selectedTag.value) tagsViewStore.delOthersVisitedViews(selectedTag.value)
tagsViewStore.delOthersCachedViews(selectedTag.value) tagsViewStore.delOthersCachedViews(selectedTag.value)
} }
/** 关闭所有标签页 */
const closeAllTags = (view: TagView) => { const closeAllTags = (view: TagView) => {
tagsViewStore.delAllVisitedViews() tagsViewStore.delAllVisitedViews()
tagsViewStore.delAllCachedViews() tagsViewStore.delAllCachedViews()
if (affixTags.some((tag) => tag.path === route.path)) { if (affixTags.some((tag) => tag.path === route.path)) return
return
}
toLastView(tagsViewStore.visitedViews, view) toLastView(tagsViewStore.visitedViews, view)
} }
/** 跳转到最后一个标签页 */
const toLastView = (visitedViews: TagView[], view: TagView) => { const toLastView = (visitedViews: TagView[], view: TagView) => {
const latestView = visitedViews.slice(-1)[0] const latestView = visitedViews.slice(-1)[0]
if (latestView !== undefined && latestView.fullPath !== undefined) { const fullPath = latestView?.fullPath
router.push(latestView.fullPath) if (fullPath !== undefined) {
router.push(fullPath)
} else { } else {
// TagsView // TagsView
if (view.name === "Dashboard") { if (view.name === "Dashboard") {
@ -113,26 +123,26 @@ const toLastView = (visitedViews: TagView[], view: TagView) => {
} }
} }
/** 打开右键菜单面板 */
const openMenu = (tag: TagView, e: MouseEvent) => { const openMenu = (tag: TagView, e: MouseEvent) => {
const menuMinWidth = 105 const menuMinWidth = 105
// container margin left //
const offsetLeft = instance!.proxy!.$el.getBoundingClientRect().left const offsetLeft = instance!.proxy!.$el.getBoundingClientRect().left
// container width //
const offsetWidth = instance!.proxy!.$el.offsetWidth const offsetWidth = instance!.proxy!.$el.offsetWidth
// left boundary //
const maxLeft = offsetWidth - menuMinWidth const maxLeft = offsetWidth - menuMinWidth
// 15: margin right //
const left15 = e.clientX - offsetLeft + 15 const left15 = e.clientX - offsetLeft + 15
if (left15 > maxLeft) { left.value = left15 > maxLeft ? maxLeft : left15
left.value = maxLeft
} else {
left.value = left15
}
top.value = e.clientY top.value = e.clientY
//
visible.value = true visible.value = true
//
selectedTag.value = tag selectedTag.value = tag
} }
/** 关闭右键菜单面板 */
const closeMenu = () => { const closeMenu = () => {
visible.value = false visible.value = false
} }
@ -148,11 +158,7 @@ watch(
) )
watch(visible, (value) => { watch(visible, (value) => {
if (value) { value ? document.body.addEventListener("click", closeMenu) : document.body.removeEventListener("click", closeMenu)
document.body.addEventListener("click", closeMenu)
} else {
document.body.removeEventListener("click", closeMenu)
}
}) })
onMounted(() => { onMounted(() => {
@ -168,10 +174,10 @@ onMounted(() => {
ref="tagRefs" ref="tagRefs"
v-for="tag in tagsViewStore.visitedViews" v-for="tag in tagsViewStore.visitedViews"
:key="tag.path" :key="tag.path"
:class="isActive(tag) ? 'active' : ''" :class="{ active: isActive(tag) }"
:to="{ path: tag.path, query: tag.query }"
class="tags-view-item" class="tags-view-item"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''" :to="{ path: tag.path, query: tag.query }"
@click.middle="!isAffix(tag) && closeSelectedTag(tag)"
@contextmenu.prevent="openMenu(tag, $event)" @contextmenu.prevent="openMenu(tag, $event)"
> >
{{ tag.meta?.title }} {{ tag.meta?.title }}
@ -180,7 +186,7 @@ onMounted(() => {
</el-icon> </el-icon>
</router-link> </router-link>
</ScrollPane> </ScrollPane>
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu"> <ul v-show="visible" class="contextmenu" :style="{ left: left + 'px', top: top + 'px' }">
<li @click="refreshSelectedTag(selectedTag)">刷新</li> <li @click="refreshSelectedTag(selectedTag)">刷新</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li>
<li @click="closeOthersTags">关闭其它</li> <li @click="closeOthersTags">关闭其它</li>