Skip to content

Commit

Permalink
refactor(Tabs): refactor Tabs (#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
xingyan95 authored Mar 15, 2022
1 parent c725114 commit 31ccca9
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 159 deletions.
30 changes: 15 additions & 15 deletions packages/devui-vue/devui/tabs/src/tab.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import { defineComponent, inject } from 'vue'
import { Tabs } from './tabs'
import { defineComponent, inject } from 'vue';
import { Tabs } from './tabs';

export default defineComponent({
name: 'DTab',
props: {
title: {
default: null,
type: [String, Number]
type: [String, Number],
},
id: {
default: null,
type: String
type: String,
},
disabled: {
type: Boolean,
default: false
}
default: false,
},
},
setup(props, { slots }) {
const tabs = inject<Tabs>('tabs')
tabs.state.slots.push(slots.dTabTitle)
tabs.state.data.push(props)
const tabs = inject<Tabs>('tabs');
tabs.state.slots.push(slots.title);
tabs.state.data.push(props);
return () => {
const { id } = props
const { id } = props;
const content =
tabs.state.showContent && tabs.state.active === id ? (
<div class='devui-tab-content'>
<div role='tabpanel' class='devui-tab-pane in active'>
{slots.default()}
</div>
</div>
) : null
return content
}
}
})
) : null;
return content;
};
},
});
166 changes: 66 additions & 100 deletions packages/devui-vue/devui/tabs/src/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,192 +1,158 @@
import {
defineComponent,
onBeforeMount,
onMounted,
onUpdated,
PropType,
provide,
reactive,
ref,
Slot
} from 'vue'
import './tabs.scss'
import { defineComponent, onBeforeMount, onMounted, onUpdated, PropType, provide, reactive, ref, Slot } from 'vue';
import './tabs.scss';

export type Active = string | number | null
export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider'
export type Active = string | number | null;
export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider';
export interface Tabs {
state: TabsState
state: TabsState;
}
interface TabsState {
data?: any[]
showContent: boolean
active: string
slots: Slot[]
data?: any[];
showContent: boolean;
active: string;
slots: Slot[];
}
export default defineComponent({
name: 'DTabs',
props: {
modelValue: {
type: [String, Number],
default: null
default: null,
},

type: {
type: String as () => TabsType,
default: 'tabs'
default: 'tabs',
},
showContent: {
type: Boolean,
default: true
default: true,
},
vertical: {
type: Boolean,
default: false
default: false,
},
reactivable: {
type: Boolean,
default: true
default: true,
},
customWidth: {
type: String,
default: ''
default: '',
},
cssClass: {
type: String,
default: ''
default: '',
},
beforeChange: {
type: Function as PropType<(id: Active) => boolean>,
default: null
}
default: null,
},
},

emits: ['update:modelValue', 'activeTabChange'],
emits: ['update:modelValue', 'active-tab-change'],
setup(props, { emit, slots }) {
const tabsEle = ref(null)
const data = reactive({ offsetLeft: 0, offsetWidth: 0, id: null })
const tabsEle = ref(null);
const data = reactive({ offsetLeft: 0, offsetWidth: 0, id: null });
const state: TabsState = reactive({
data: [],
active: props.modelValue,
showContent: props.showContent,
slots: []
})
slots: [],
});
provide<Tabs>('tabs', {
state
})
state,
});

const canChange = function (currentTab: Active) {
let changeResult = Promise.resolve(true)
let changeResult = Promise.resolve(true);
if (typeof props.beforeChange === 'function') {
const result: any = props.beforeChange(currentTab)
const result: any = props.beforeChange(currentTab);
if (typeof result !== 'undefined') {
if (result.then) {
changeResult = result
changeResult = result;
} else {
console.log(result)
changeResult = Promise.resolve(result)
changeResult = Promise.resolve(result);
}
}
}

return changeResult
}
return changeResult;
};
const activeClick = function (item, tabEl?) {
if (!props.reactivable && props.modelValue === item.id) {
return
return;
}
canChange(item.id).then((change) => {
if (!change) {
return
return;
}
const tab = state.data.find((itemOption) => itemOption.id === item.id)
const tab = state.data.find((itemOption) => itemOption.id === item.id);
if (tab && !tab.disabled) {
state.active = item.id
emit('update:modelValue', tab.id)
state.active = item.id;
emit('update:modelValue', tab.id);
if (props.type === 'slider' && tabEl && tabsEle) {
this.offsetLeft =
tabEl.getBoundingClientRect().left -
this.tabsEle.nativeElement.getBoundingClientRect().left
this.offsetWidth = tabEl.getBoundingClientRect().width
this.offsetLeft = tabEl.getBoundingClientRect().left - this.tabsEle.nativeElement.getBoundingClientRect().left;
this.offsetWidth = tabEl.getBoundingClientRect().width;
}
emit('activeTabChange', tab.id)
emit('active-tab-change', tab.id);
}
})
}
const ulClass: string[] = [props.type]
props.cssClass && ulClass.push(props.cssClass)
props.vertical && ulClass.push('devui-nav-stacked')
});
};
const ulClass: string[] = [props.type];
props.cssClass && ulClass.push(props.cssClass);
props.vertical && ulClass.push('devui-nav-stacked');
onUpdated(() => {
if (props.type === 'slider') {
// 延时等待active样式切换至正确的tab
setTimeout(() => {
const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active')
const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active');
if (tabEle) {
data.offsetLeft =
tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left
data.offsetWidth = tabEle.getBoundingClientRect().width
data.offsetLeft = tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left;
data.offsetWidth = tabEle.getBoundingClientRect().width;
}
})
});
}
})
});
onBeforeMount(() => {
if (props.type !== 'slider' && props.modelValue === undefined && state.data.length > 0) {
activeClick(state.data[0])
activeClick(state.data[0]);
}
})
});
onMounted(() => {
if (
props.type === 'slider' &&
props.modelValue === undefined &&
state.data.length > 0 &&
state.data[0]
) {
activeClick(state.data[0].tabsEle.value.getElementById(state.data[0].tabId))
if (props.type === 'slider' && props.modelValue === undefined && state.data.length > 0 && state.data[0]) {
activeClick(state.data[0].tabsEle.value.getElementById(state.data[0].tabId));
}
})
});
return () => {
return (
<div>
<ul
ref={tabsEle}
role='tablist'
class={`devui-nav devui-nav-${ulClass.join(' ')}`}
id='devuiTabs11'
>
<ul ref={tabsEle} role='tablist' class={`devui-nav devui-nav-${ulClass.join(' ')}`} id='devuiTabs11'>
{state.data.map((item, i) => {
return (
<li
role='presentation'
onClick={() => {
activeClick(item)
activeClick(item);
}}
class={
(props.modelValue === (item.id || item.tabId) ? 'active' : '') +
' ' +
(item.disabled ? 'disabled' : '')
}
id={item.id || item.tabId}
>
<a
role='tab'
data-toggle={item.id}
aria-expanded={props.modelValue === (item.id || item.tabId)}
>
class={(props.modelValue === (item.id || item.tabId) ? 'active' : '') + ' ' + (item.disabled ? 'disabled' : '')}
id={item.id || item.tabId}>
<a role='tab' data-toggle={item.id} aria-expanded={props.modelValue === (item.id || item.tabId)}>
{state.slots[i] ? state.slots[i]() : <span>{item.title}</span>}
</a>
</li>
)
);
})}
<div
class={`devui-nav-${props.type}-animation`}
style={{
left: data.offsetLeft + 'px',
width: data.offsetWidth + 'px'
}}
></div>
width: data.offsetWidth + 'px',
}}></div>
</ul>
{slots.default()}
</div>
)
}
}
})
);
};
},
});
Loading

0 comments on commit 31ccca9

Please sign in to comment.