UNPKG

@fesjs/fes-design

Version:
175 lines (171 loc) 6.54 kB
import { defineComponent, ref, computed, provide, toRef, watch, nextTick, createVNode, mergeProps, TransitionGroup } from 'vue'; import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties'; import { UPDATE_MODEL_EVENT, CHANGE_EVENT, CLOSE_EVENT } from '../_util/constants'; import getPrefixCls from '../_util/getPrefixCls'; import { useNormalModel } from '../_util/use/useModel'; import { flatten } from '../_util/vnode'; import { useTheme } from '../_theme/useTheme'; import PlusOutlined from '../icon/PlusOutlined'; import Scrollbar from '../scrollbar'; import { COMPONENT_NAME, ADD_EVENT, CLICK_TAB_EVENT, TABS_INJECTION_KEY } from './constants'; import { mapTabPane } from './helper'; import Tab from './tab'; import TabPane from './tab-pane.js'; import { tabsProps } from './props'; const _excluded = ["render", "renderTab"]; const prefixCls = getPrefixCls('tabs'); var tabs = defineComponent({ name: COMPONENT_NAME, props: tabsProps, emits: [UPDATE_MODEL_EVENT, CHANGE_EVENT, CLOSE_EVENT, ADD_EVENT, CLICK_TAB_EVENT], setup(props, _ref) { let { emit, slots } = _ref; useTheme(); const [currentValue, updateCurrentValue] = useNormalModel(props, emit); const tabPaneLazyCache = {}; const tabRefs = ref([]); const tabNavRef = ref(null); const tabsLength = ref(0); const isCard = computed(() => props.type === 'card'); const position = computed(() => isCard.value ? 'top' : props.position); const setTabRefs = (el, index) => { if (el) { tabRefs.value[index] = el; } }; const handleTabClick = key => { if (key !== currentValue.value) { updateCurrentValue(key); emit(CHANGE_EVENT, key); } emit(CLICK_TAB_EVENT, key); }; const handleAddClick = event => { emit(ADD_EVENT, event); }; const handleClose = key => { emit(CLOSE_EVENT, key); }; const autoScrollTab = el => { if (!tabNavRef.value || !el) { return; } const { scrollLeft, scrollTop, offsetWidth, offsetHeight } = tabNavRef.value.containerRef; if (['top', 'bottom'].includes(props.position) && (scrollLeft + offsetWidth < el.offsetLeft + el.offsetWidth || el.offsetLeft < scrollLeft)) { tabNavRef.value.setScrollLeft(el.offsetLeft - offsetWidth + el.offsetWidth, 0); } else if (['left', 'right'].includes(props.position) && (scrollTop + offsetHeight < el.offsetTop + el.offsetHeight || el.offsetTop < scrollTop)) { tabNavRef.value.setScrollTop(el.offsetTop - offsetHeight + el.offsetHeight, 0); } }; // 当没有默认值时,设置第一项为默认值,在Tab组件调用 const setDefaultValue = value => { if (!currentValue.value && currentValue.value !== 0) { updateCurrentValue(value); } }; provide(TABS_INJECTION_KEY, { valueRef: currentValue, closableRef: toRef(props, 'closable'), closeModeRef: toRef(props, 'closeMode'), isCard, tabsLength, handleTabClick, handleClose, setDefaultValue }); watch(() => [currentValue.value, position.value], () => { nextTick(() => { const tab = tabRefs.value.find(item => item.value === currentValue.value); autoScrollTab(tab === null || tab === void 0 ? void 0 : tab.$el); }); }, { immediate: true }); const mergeRenderPanes = () => { var _props$panes; const children = slots.default && flatten(slots.default()).filter(vNode => vNode.type.name === 'FTabPane') || []; if ((_props$panes = props.panes) !== null && _props$panes !== void 0 && _props$panes.length) { return children.concat(props.panes.map(pane => { const { render, renderTab } = pane, paneProps = _objectWithoutProperties(pane, _excluded); if (!render) { console.warn(`[${COMPONENT_NAME}]: panes 需要提供 render`); } const slots = { default: () => render === null || render === void 0 ? void 0 : render(paneProps), tab: renderTab ? () => renderTab(paneProps) : null }; return createVNode(TabPane, mergeProps(paneProps, { "value": paneProps.value }), slots); })); } return children; }; return () => { const children = mergeRenderPanes(); let navItems = children.map((vNode, index) => { var _vNode$children; const tabSlot = (_vNode$children = vNode.children) === null || _vNode$children === void 0 ? void 0 : _vNode$children.tab; return createVNode(Tab, mergeProps(vNode.props, { "ref": el => setTabRefs(el, index) }), { default: tabSlot }); }); if (isCard.value) { if (props.addable) { navItems.push(createVNode("div", { "onClick": handleAddClick, "class": `${prefixCls}-tab ${prefixCls}-tab-card addable` }, [createVNode(PlusOutlined, null, null)])); } // 添加 card pad navItems = navItems.map((item, index) => [item, createVNode("div", { "class": index !== navItems.length - 1 ? `${prefixCls}-tab-pad` : `${prefixCls}-tab-pad--last` }, null)]).flat(1); } return createVNode("div", { "class": { [`${prefixCls}`]: true, [`${prefixCls}-${position.value}`]: true, [`${prefixCls}-card`]: isCard.value } }, [createVNode("div", { "class": `${prefixCls}-nav` }, [slots.prefix && createVNode("div", { "class": `${prefixCls}-nav-prefix` }, [slots.prefix()]), createVNode(Scrollbar, { "ref": tabNavRef, "class": `${prefixCls}-nav-scroll`, "shadow": true }, { default: () => [createVNode("div", { "class": `${prefixCls}-nav-scroll-content` }, [navItems])] }), slots.suffix && createVNode("div", { "class": `${prefixCls}-nav-suffix` }, [slots.suffix()])]), createVNode("div", { "class": `${prefixCls}-tab-pane-wrapper` }, [createVNode(TransitionGroup, { "name": props.transition ? props.transition === true ? `${prefixCls}-slide-fade` : props.transition : null }, { default: () => [mapTabPane(mergeRenderPanes(), // TODO: 待优化 currentValue.value, tabPaneLazyCache)] })])]); }; } }); export { tabs as default };