perf: optimize ScrooX component.

This commit is contained in:
张传龙 2022-07-09 14:38:38 +08:00
parent a1db8273f5
commit 76c3f0b64c
2 changed files with 26 additions and 41 deletions

View File

@ -1,20 +1,19 @@
<template> <template>
<div ref="wrapper" class="tags-wrapper" @mousewheel.prevent="handleMouseWheel"> <div ref="wrapper" class="wrapper" @mousewheel.prevent="handleMouseWheel">
<template v-if="showArrow && isOverflow"> <template v-if="showArrow && isOverflow">
<div class="left" @click="handleMouseWheel({ wheelDelta: 50 })"> <div class="left" @click="handleMouseWheel({ wheelDelta: 120 })">
<icon-ic:baseline-keyboard-arrow-left /> <icon-ic:baseline-keyboard-arrow-left />
</div> </div>
<div class="right" @click="handleMouseWheel({ wheelDelta: -50 })"> <div class="right" @click="handleMouseWheel({ wheelDelta: -120 })">
<icon-ic:baseline-keyboard-arrow-right /> <icon-ic:baseline-keyboard-arrow-right />
</div> </div>
</template> </template>
<div <div
ref="content" ref="content"
class="tags-content" class="content"
:class="{ overflow: isOverflow && showArrow }" :class="{ overflow: isOverflow && showArrow }"
:style="{ :style="{
height: height + 'px',
transform: `translateX(${translateX}px)`, transform: `translateX(${translateX}px)`,
}"> }">
<slot /> <slot />
@ -24,37 +23,23 @@
<script setup> <script setup>
import { debounce } from '@/utils' import { debounce } from '@/utils'
import { isNullOrUndef } from '@/utils/is'
defineProps({ defineProps({
height: {
type: Number,
default: 50,
},
showArrow: { showArrow: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
}) })
onMounted(() => {
refreshIsOverflow()
})
const translateX = ref(0) const translateX = ref(0)
const content = ref(null) const content = ref(null)
const wrapper = ref(null) const wrapper = ref(null)
const isOverflow = ref(false) const isOverflow = ref(false)
function refreshIsOverflow(isIncrease) { const refreshIsOverflow = debounce(() => {
isOverflow.value = content.value.offsetWidth > wrapper.value.offsetWidth isOverflow.value = content.value.offsetWidth > wrapper.value.offsetWidth
if (isNullOrUndef(isIncrease)) return }, 200)
if (isOverflow.value) {
handleMouseWheel({ wheelDelta: isIncrease ? -100 : 100 })
} else if (!isIncrease && translateX.value < 0) {
handleMouseWheel({ wheelDelta: 100 })
}
}
function handleMouseWheel(e) { function handleMouseWheel(e) {
const { wheelDelta } = e const { wheelDelta } = e
const wrapperWidth = wrapper.value.offsetWidth const wrapperWidth = wrapper.value.offsetWidth
@ -65,15 +50,15 @@ function handleMouseWheel(e) {
* @wrapperWidth 容器的宽度 * @wrapperWidth 容器的宽度
* @contentWidth 内容的宽度 * @contentWidth 内容的宽度
*/ */
if (wheelDelta < 0 && -translateX.value > contentWidth - wrapperWidth + 10) { if (wheelDelta < 0) {
return if (wrapperWidth > contentWidth && translateX.value < -10) return
if (wrapperWidth <= contentWidth && contentWidth + translateX.value - wrapperWidth < -10) return
} }
if (wheelDelta > 0 && translateX.value > 10) { if (wheelDelta > 0 && translateX.value > 10) {
return return
} }
translateX.value += wheelDelta translateX.value += wheelDelta
resetTranslateX(wrapperWidth, contentWidth) resetTranslateX(wrapperWidth, contentWidth)
} }
@ -87,20 +72,29 @@ const resetTranslateX = debounce(function (wrapperWidth, contentWidth) {
} }
}, 200) }, 200)
defineExpose({ const observer = new MutationObserver(refreshIsOverflow)
refreshIsOverflow, onMounted(() => {
refreshIsOverflow()
window.addEventListener('resize', refreshIsOverflow)
//
observer.observe(content.value, { childList: true })
})
onBeforeUnmount(() => {
window.removeEventListener('resize', refreshIsOverflow)
observer.disconnect()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tags-wrapper { .wrapper {
display: flex; display: flex;
background-color: #fff; background-color: #fff;
position: sticky;
top: 0;
z-index: 9; z-index: 9;
overflow: hidden; overflow: hidden;
.tags-content { position: relative;
.content {
padding: 0 10px; padding: 0 10px;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,5 +1,5 @@
<template> <template>
<ScrollX ref="scrollX" :height="useTheme.tags.height"> <ScrollX :class="`h-${useTheme.tags.height}`">
<n-tag <n-tag
v-for="tag in tagsStore.tags" v-for="tag in tagsStore.tags"
:key="tag.path" :key="tag.path"
@ -47,15 +47,6 @@ watch(
{ immediate: true } { immediate: true }
) )
const scrollX = ref(null)
watch(
() => tagsStore.tags,
async (newVal, oldVal) => {
await nextTick()
scrollX.value?.refreshIsOverflow(newVal.length > oldVal.length)
}
)
const handleTagClick = (path) => { const handleTagClick = (path) => {
tagsStore.setActiveTag(path) tagsStore.setActiveTag(path)
router.push(path) router.push(path)