Skip to content

Commit

Permalink
fix(comp:tabs): offset error when setting selectedKey
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzaijiang committed Oct 28, 2022
1 parent 677b163 commit c90ea23
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 44 deletions.
14 changes: 9 additions & 5 deletions packages/components/tabs/demo/Scroll.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<IxTab v-for="panel in panels" :key="panel" :title="'Tab ' + panel"> Content of Tab {{ panel }} </IxTab>
</IxTabs>
<IxSpace align="center">
<IxButton @click="onOpen">addTab</IxButton>
<IxButton @click="addTab">addTab</IxButton>
<IxButton @click="closeTab">closeTab</IxButton>
移动到第几个:<IxInputNumber v-model:value="selectedKey" :max="20" :min="1"></IxInputNumber>
</IxSpace>
Expand All @@ -23,13 +23,17 @@
<script setup lang="ts">
import { ref } from 'vue'
const selectedKey = ref(1)
const selectedKey = ref(7)
const panels = ref([1, 2, 3])
const onOpen = () => {
panels.value.push((panels.value[panels.value.length - 1] || 0) + 1)
const panels = ref([1, 2, 3, 4, 5, 6, 7])
const addTab = () => {
const key = (panels.value[panels.value.length - 1] || 0) + 1
panels.value.push(key)
selectedKey.value = key
}
const closeTab = () => {
panels.value.pop()
const key = panels.value[panels.value.length - 1]
selectedKey.value = key
}
</script>
68 changes: 42 additions & 26 deletions packages/components/tabs/src/InternalTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,33 @@ export default defineComponent({

const [navOffset, setNavOffset] = useState(0)
const [barStyle, setBarStyle] = useState<CSSProperties>({})
const { navSize, navWrapperSize, navPreNextSize, selectedElSize, syncNavElSize, syncSelectedElSize } =
useNavRelatedElSize(isHorizontal, navWrapperElRef, navElRef, navPreElRef, selectedElRef)
const { selectedElOffset, syncSelectedElOffset } = useSelectedElOffset(isHorizontal, navPreNextSize, selectedElRef)
const {
navSize,
navWrapperSize,
navPreNextSize,
selectedElSize,
setNavElSize,
setSelectedElSize,
setNavPreNextElSize,
} = useNavRelatedElSize(isHorizontal, navWrapperElRef, navElRef, navPreElRef, selectedElRef)
const { selectedElOffset, setSelectedElOffset } = useSelectedElOffset(isHorizontal, navPreNextSize, selectedElRef)

const hasScroll = computed(() => {
return navSize.value! > navWrapperSize.value
return navSize.value > navWrapperSize.value
})

watch(
hasScroll,
() => {
setNavPreNextElSize()
updateNavBarStyle()
updateSelectedOffset()
},
{
flush: 'post',
},
)

const selectedElVisibleSize = useSelectedElVisibleSize(navWrapperSize, selectedElOffset, navOffset)

// 处理存在滚动状态下,滚动到被选中的tab,并修正其位置
Expand Down Expand Up @@ -135,6 +154,14 @@ export default defineComponent({
})
})

const navWrapperClass = computed(() => {
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[`${prefixCls}-nav-wrapper`]: true,
[`${prefixCls}-nav-wrapper-has-scroll`]: hasScroll.value,
})
})

const curryNavPreNextClasses = curry(useNavPreNextClasses)(props, mergedPrefixCls)
const navPreClasses = curryNavPreNextClasses('pre', preReached)
const navNextClasses = curryNavPreNextClasses('next', nextReached)
Expand Down Expand Up @@ -203,9 +230,10 @@ export default defineComponent({
}

const update = () => {
syncNavElSize()
syncSelectedElSize()
syncSelectedElOffset()
setNavElSize()
setNavPreNextElSize()
setSelectedElSize()
setSelectedElOffset()
updateNavBarStyle()
judgePreNextStatus()
}
Expand Down Expand Up @@ -239,19 +267,11 @@ export default defineComponent({

watch(
navSize,
(val, oldSize) => {
(currentSize, oldSize) => {
let offset = navOffset.value
const currentSize = val!
if (currentSize > oldSize && isAddTabs) {
offset += currentSize - oldSize
if (hasScroll.value) {
setNavOffset(offset)
}
} else if (currentSize < oldSize && !isAddTabs) {
if (currentSize < oldSize && !isAddTabs) {
offset += currentSize - oldSize
if (offset >= 0) {
setNavOffset(offset)
}
setNavOffset(offset > 0 ? offset : 0)
}
},
{
Expand All @@ -271,8 +291,9 @@ export default defineComponent({
watch(
selectedElRef,
() => {
syncSelectedElSize()
syncSelectedElOffset()
setSelectedElSize()
setSelectedElOffset()
setSelectedElOffset()
updateSelectedOffset()
updateNavBarStyle()
},
Expand Down Expand Up @@ -305,12 +326,7 @@ export default defineComponent({

return (
<div class={classes.value}>
<div
class={`${mergedPrefixCls.value}-nav-wrapper ${
hasScroll.value ? `${mergedPrefixCls.value}-nav-wrapper-has-scroll` : ''
}`}
ref={navWrapperElRef}
>
<div class={navWrapperClass.value} ref={navWrapperElRef}>
{hasScroll.value && (
<IxIcon
class={navPreClasses.value}
Expand Down
6 changes: 3 additions & 3 deletions packages/components/tabs/src/composables/useOffset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useState } from '@idux/cdk/utils'

export interface Offset {
selectedElOffset: ComputedRef<number>
syncSelectedElOffset: () => void
setSelectedElOffset: () => void
}

export function useSelectedElOffset(
Expand All @@ -26,13 +26,13 @@ export function useSelectedElOffset(
() => (isHorizontal.value ? selectedLeft.value : selectedTop.value) + navPreNextSize.value,
)

const syncSelectedElOffset = () => {
const setSelectedElOffset = () => {
setSelectedLeft(selectedElRef.value?.offsetLeft ?? 0)
setSelectedTop(selectedElRef.value?.offsetTop ?? 0)
}

return {
selectedElOffset,
syncSelectedElOffset,
setSelectedElOffset,
}
}
21 changes: 11 additions & 10 deletions packages/components/tabs/src/composables/useSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import type { IconInstance } from '@idux/components/icon'

import { type ComputedRef, type Ref, computed, watchEffect } from 'vue'
import { type ComputedRef, type Ref, computed } from 'vue'

import { useState } from '@idux/cdk/utils'

Expand All @@ -16,8 +16,9 @@ export interface NavRelatedElSize {
navWrapperSize: ComputedRef<number>
navPreNextSize: ComputedRef<number>
selectedElSize: ComputedRef<number>
syncNavElSize: () => void
syncSelectedElSize: () => void
setNavElSize: () => void
setSelectedElSize: () => void
setNavPreNextElSize: () => void
}

export function useNavRelatedElSize(
Expand All @@ -43,32 +44,32 @@ export function useNavRelatedElSize(
const selectedElSize = computed(() => (isHorizontal.value ? selectedWidth.value : selectedHeight.value))

// dom 的size无法响应式获取,只能手动获取
const syncNavElSize = () => {
const setNavElSize = () => {
setNavWrapperWidth(navWrapperElRef.value?.offsetWidth ?? 0)
setNavWrapperHeight(navWrapperElRef.value?.offsetHeight ?? 0)

setNavWidth(navElRef.value?.offsetWidth ?? 0)
setNavHeight(navElRef.value?.offsetHeight ?? 0)
}

const syncSelectedElSize = () => {
const setSelectedElSize = () => {
setSelectedWidth(selectedElRef.value?.offsetWidth ?? 0)
setSelectedHeight(selectedElRef.value?.offsetHeight ?? 0)
}

// 向前、向后按钮是动态渲染的,所以可以使用 watchEffect 获取其size
watchEffect(() => {
const setNavPreNextElSize = () => {
setNavPreNextWidth(navPreElRef.value?.$el.offsetWidth ?? 0)
setNavPreNextHeight(navPreElRef.value?.$el.offsetHeight ?? 0)
})
}

return {
navSize,
navWrapperSize,
navPreNextSize,
selectedElSize,
syncNavElSize,
syncSelectedElSize,
setNavElSize,
setSelectedElSize,
setNavPreNextElSize,
}
}

Expand Down

0 comments on commit c90ea23

Please sign in to comment.