Skip to content

Commit

Permalink
fix(tabs): change tab navs dom to method render (#2595)
Browse files Browse the repository at this point in the history
  • Loading branch information
uyarn authored Jul 19, 2023
1 parent 1e4c297 commit f516ae8
Showing 1 changed file with 55 additions and 39 deletions.
94 changes: 55 additions & 39 deletions src/tabs/tab-nav.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
import { VNode } from 'vue';
import debounce from 'lodash/debounce';
import {
ChevronLeftIcon as TdChevronLeftIcon,
ChevronRightIcon as TdChevronRightIcon,
AddIcon as TdAddIcon,
} from 'tdesign-icons-vue';
import type { ComponentPublicInstance } from '@vue/composition-api';
import TTabPanel from './tab-panel';
import TTabNavItem from './tab-nav-item';
import { emitEvent } from '../utils/event';
import { firstUpperCase } from '../utils/helper';
import { TdTabsProps, TdTabPanelProps } from './type';
import tabProps from './props';
import { renderTNodeJSX } from '../utils/render-tnode';
import { TabPanelProps } from '.';
import { getClassPrefixMixins, getGlobalIconMixins } from '../config-provider/config-receiver';
import mixins from '../utils/mixins';

import type { TdTabsProps } from './type';

const classPrefixMixins = getClassPrefixMixins('tab__nav');

const getDomWidth = (dom: HTMLElement): number => dom?.offsetWidth || 0;

const getActiveTabEl = (navs: Array<VNode>, value: TabPanelProps['value']): HTMLElement => {
for (let i = 0; i < navs.length; i++) {
if ((navs[i].componentOptions.propsData as TdTabPanelProps).value === value) {
return navs[i].componentInstance?.$el as HTMLElement;
}
}
return null;
};

interface GetLeftCoverWidth {
leftZone: HTMLElement;
leftIcon: HTMLElement;
Expand Down Expand Up @@ -94,24 +85,19 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
};
},
computed: {
navs(): Array<VNode> {
return this.panels.map((panel, index) => (
<TTabNavItem
ref={`tabItem${index}`}
key={panel.value}
index={index}
theme={this.theme}
size={this.size}
placement={this.placement}
label={renderTNodeJSX(panel, 'label', `选项卡${index + 1}`)}
active={panel.value === this.value}
disabled={this.disabled || panel.disabled}
removable={panel.removable}
value={panel.value}
onClick={(e: MouseEvent) => this.tabClick(e, panel)}
onRemove={this.removeBtnClick}
></TTabNavItem>
));
navs(): Array<Record<string, any>> {
return this.panels.map((panel, index) => ({
ref: `tabItem${index}`,
key: panel.value,
theme: this.theme,
size: this.size,
placement: this.placement,
active: panel.value === this.value,
disabled: this.disabled || panel.disabled,
removable: panel.removable,
value: panel.value,
panel,
}));
},
wrapTransformStyle(): { [key: string]: string } {
if (['left', 'right'].includes(this.placement.toLowerCase())) return {};
Expand Down Expand Up @@ -177,6 +163,13 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
navsContainerStyle(): object {
return this.addable ? { 'min-height': '48px' } : null;
},
activeElement(): HTMLElement {
const activeIndx = this.navs.findIndex((nav) => nav.active);
if (activeIndx > -1) {
return (this.$refs[`tabItem${activeIndx}`] as unknown as ComponentPublicInstance)?.$el;
}
return null;
},
},
watch: {
dataCanUpdateArrow() {
Expand Down Expand Up @@ -244,18 +237,24 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
return ['width', 'left'];
};
let offset = 0;
const { activeElement } = this;
if (!activeElement) return {};

const [sizePropName, offsetPropName] = getPropName();
let i = 0;
for (; i < this.navs.length; i++) {
if ((this.navs[i].componentInstance as InstanceType<typeof TTabPanel>)?.value === this.value) {
if (this.navs[i].active) {
break;
}
offset += this.navs[i].componentInstance?.$el?.[`client${firstUpperCase(sizePropName)}`] || 0;
offset
+= (this.$refs[`tabItem${i}`] as unknown as ComponentPublicInstance)?.$el?.[
`client${firstUpperCase(sizePropName)}`
] || 0;
}
if (!this.navs[i]) return {};

return {
[offsetPropName]: `${offset}px`,
[sizePropName]: `${this.navs[i].componentInstance?.$el?.[`client${firstUpperCase(sizePropName)}`] || 0}px`,
[sizePropName]: `${activeElement?.[`client${firstUpperCase(sizePropName)}`] || 0}px`,
};
};
this.navBarStyle = getNavBarStyle();
Expand All @@ -265,7 +264,7 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
if (['left', 'right'].includes(this.placement.toLowerCase())) return;

const container = this.$refs.navsContainer as HTMLElement;
const activeTabEl: HTMLElement = getActiveTabEl(this.navs, this.value);
const activeTabEl: HTMLElement = this.activeElement;
const totalWidthBeforeActiveTab = activeTabEl?.offsetLeft;
const containerWidth = getDomWidth(container);
if (totalWidthBeforeActiveTab > containerWidth) this.scrollLeft = totalWidthBeforeActiveTab;
Expand Down Expand Up @@ -360,7 +359,7 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
if (['left', 'right'].includes(this.placement)) {
return false;
}
const activeTabEl: HTMLElement = getActiveTabEl(this.navs, this.value);
const activeTabEl: HTMLElement = this.activeElement;
if (!activeTabEl) {
// 如果没有当前 value 对应的tab,一种情况是真没有;一种情况是在修改value的同时,新增了一个值为该value的tab。后者因为navs的更新在$nextTick之后,所以得等下一个updated才能拿到新的tab
if (needCheckUpdate) {
Expand Down Expand Up @@ -418,14 +417,31 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
removeBtnClick({ e, value, index }: Parameters<TdTabsProps['onRemove']>[0]) {
emitEvent<Parameters<TdTabsProps['onRemove']>>(this, 'remove', { e, value, index });
},

renderPanelContent() {
return this.navs.map((panel, index) => (
<TTabNavItem
ref={`tabItem${index}`}
index={index}
key={panel.value}
theme={panel.theme}
size={panel.size}
placement={panel.placement}
active={panel.active}
disabled={panel.disabled}
removable={panel.removable}
value={panel.value}
label={renderTNodeJSX(panel.panel, 'label', `选项卡${index + 1}`)}
onClick={(e: MouseEvent) => this.tabClick(e, panel.panel)}
onRemove={this.removeBtnClick}
></TTabNavItem>
));
},
renderArrows() {
const { ChevronLeftIcon, ChevronRightIcon, AddIcon } = this.useGlobalIcon({
ChevronLeftIcon: TdChevronLeftIcon,
ChevronRightIcon: TdChevronRightIcon,
AddIcon: TdAddIcon,
});

return [
<div
ref="leftOperationsZone"
Expand Down Expand Up @@ -464,7 +480,7 @@ export default mixins(classPrefixMixins, getGlobalIconMixins()).extend({
<div class={this.navScrollContainerClass}>
<div ref="navsWrap" class={this.navsWrapClass} style={this.wrapTransformStyle}>
{this.renderNavBar()}
{this.navs}
{this.renderPanelContent()}
</div>
</div>
</div>
Expand Down

0 comments on commit f516ae8

Please sign in to comment.