perf: 优化多标签滚动

This commit is contained in:
张传龙
2022-06-11 20:17:30 +08:00
parent 67d966e096
commit 0636ac4716
7 changed files with 196 additions and 89 deletions

View File

@@ -5,5 +5,6 @@ import SideMenu from './components/SideMenu.vue'
<template>
<SideLogo />
<div h-1 bg-gray-200></div>
<SideMenu />
</template>

View File

@@ -1,27 +1,17 @@
<template>
<div ref="tagsWrapper" class="tags-wrapper" @mousewheel.prevent="handleMouseWheel">
<div
ref="tagsContent"
class="tags-content"
:style="{
height: useTheme.tags.height + 'px',
transform: `translateX(${translateX}px)`,
}"
:wrap="false"
<ScrollX ref="scrollX" :height="useTheme.tags.height">
<n-tag
v-for="tag in tagsStore.tags"
:key="tag.path"
:type="tagsStore.activeTag === tag.path ? 'primary' : 'default'"
:closable="tagsStore.tags.length > 1"
@click="handleTagClick(tag.path)"
@close.stop="tagsStore.removeTag(tag.path)"
@contextmenu.prevent="handleContextMenu($event, tag)"
>
<n-tag
v-for="tag in tagsStore.tags"
:key="tag.path"
:type="tagsStore.activeTag === tag.path ? 'primary' : 'default'"
:closable="tagsStore.tags.length > 1"
@click="handleTagClick(tag.path)"
@close.stop="tagsStore.removeTag(tag.path)"
@contextmenu.prevent="handleContextMenu($event, tag)"
>
{{ tag.title }}
</n-tag>
</div>
</div>
{{ tag.title }}
</n-tag>
</ScrollX>
<ContextMenu
v-model:show="contextMenuOption.show"
@@ -37,6 +27,7 @@ import { nextTick, reactive, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTagsStore } from '@/store/modules/tags'
import { useThemeStore } from '@/store/modules/theme'
import ScrollX from '@/components/Common/ScrollX.vue'
const route = useRoute()
const router = useRouter()
@@ -49,9 +40,6 @@ const contextMenuOption = reactive({
y: 0,
currentPath: '',
})
let translateX = ref(0)
const tagsContent = ref()
const tagsWrapper = ref()
watch(
() => route.path,
@@ -63,6 +51,15 @@ watch(
{ immediate: true }
)
const scrollX = ref(null)
watch(
() => tagsStore.tags,
async (newVal, oldVal) => {
await nextTick()
scrollX.value?.refreshIsOverflow(newVal.length > oldVal.length)
}
)
const handleTagClick = (path) => {
tagsStore.setActiveTag(path)
router.push(path)
@@ -86,74 +83,27 @@ async function handleContextMenu(e, tagItem) {
await nextTick()
showContextMenu()
}
function handleMouseWheel(e) {
let { wheelDelta } = e
const tagsWrapperWidth = tagsWrapper.value.offsetWidth
const tagsContentWidth = tagsContent.value.offsetWidth
/**
* @wheelDelta 平行滚动的值 >0 右移 <0: 左移
* @translateX 内容translateX的值
* @tagsWrapperWidth 容器的宽度
* @tagsContentWidth 内容的宽度
*/
// 向右移动时时,如果无偏移或者向左偏移,则不处理
if (wheelDelta > 0 && translateX.value >= 0) {
return
}
// 向左移动时,如果内容的宽度小于向左偏移的宽度+容器的宽度,则不处理
if (wheelDelta < 0 && tagsWrapperWidth > tagsContentWidth + translateX.value) {
return
}
if (wheelDelta > 0 && wheelDelta + translateX.value > 0) {
wheelDelta = -translateX.value
}
if (wheelDelta < 0 && -wheelDelta > tagsWrapperWidth - (tagsContentWidth + translateX.value)) {
wheelDelta = tagsWrapperWidth - (tagsContentWidth + translateX.value)
}
translateX.value += wheelDelta
}
</script>
<style lang="scss">
.tags-wrapper {
display: flex;
background-color: #fff;
position: sticky;
top: 0;
z-index: 9;
overflow: hidden;
.tags-content {
padding: 0 10px;
display: flex;
align-items: center;
flex-wrap: nowrap;
transition: transform 0.3s;
}
.n-tag {
padding: 0 15px;
margin: 0 5px;
cursor: pointer;
.n-tag__close {
margin-left: 5px;
box-sizing: content-box;
font-size: 12px;
padding: 2px;
border-radius: 50%;
transition: all 0.7s;
&:hover {
color: #fff;
background-color: $primaryColor;
}
}
.n-tag {
padding: 0 15px;
margin: 0 5px;
cursor: pointer;
.n-tag__close {
margin-left: 5px;
box-sizing: content-box;
font-size: 12px;
padding: 2px;
border-radius: 50%;
transition: all 0.7s;
&:hover {
color: $primaryColor;
color: #fff;
background-color: $primaryColor;
}
}
&:hover {
color: $primaryColor;
}
}
</style>