@fesjs/fes-design
Version:
fes-design for PC
192 lines (189 loc) • 6.33 kB
JavaScript
import { defineComponent, getCurrentInstance, ref, computed, onMounted, onBeforeUnmount, provide, watch, createVNode, mergeProps, Fragment, withDirectives, vShow } from 'vue';
import { pick } from 'lodash-es';
import getPrefixCls from '../_util/getPrefixCls';
import FadeInExpandTransition from '../_util/components/fadeInExpandTransition';
import Popper from '../popper/popper';
import DownOutlined from '../icon/DownOutlined';
import RightOutlined from '../icon/RightOutlined';
import Ellipsis from '../ellipsis/ellipsis';
import { COMPONENT_NAME, SUB_MENU_KEY } from './const';
import useChildren from './useChildren';
import useParent from './useParent';
import useMenu from './useMenu';
const prefixCls = getPrefixCls('sub-menu');
const subMenuProps = {
value: {
type: [String, Number]
},
label: String
};
var subMenu = defineComponent({
name: COMPONENT_NAME.SUB_MENU,
components: {
Ellipsis,
FadeInExpandTransition
},
props: {
value: {
type: [String, Number],
default: null
},
label: String
},
setup(props, _ref) {
let {
slots
} = _ref;
const instance = getCurrentInstance();
const {
indexPath
} = useMenu(instance);
const subMenuRef = ref(null);
const {
rootMenu,
parentMenu,
paddingStyle,
isFirstLevel,
onlyIcon
} = useChildren(indexPath);
// 根节点 menu
if (!rootMenu) {
console.warn(`[${COMPONENT_NAME.SUB_MENU}] must be a child of ${COMPONENT_NAME.MENU}`);
}
// 父级组件,可能为 menu 或者 sub-menu
if (!parentMenu) {
console.warn(`[${COMPONENT_NAME.SUB_MENU}] must be a child of ${COMPONENT_NAME.MENU} or ${COMPONENT_NAME.SUB_MENU}`);
}
const {
children
} = useParent();
const isOpened = ref(false);
const isActive = computed(() => children.some(child => child === null || child === void 0 ? void 0 : child.isActive));
const subMenu = {
uid: instance.uid,
value: props.value,
type: 'subMenu',
children,
isOpened,
isActive
};
onMounted(() => {
parentMenu.addChild(subMenu);
});
onBeforeUnmount(() => {
parentMenu.removeChild(subMenu);
});
provide(SUB_MENU_KEY, {
handleItemClick: () => {
if (rootMenu.renderWithPopper.value) {
isOpened.value = false;
rootMenu.updateExpandedKeys([]);
}
}
});
const placement = computed(() => {
if (rootMenu.props.mode === 'horizontal') {
return isFirstLevel.value ? 'bottom-start' : 'right-start';
}
return 'right-start';
});
const classList = computed(() => [prefixCls, isActive.value && 'is-active'].filter(Boolean).join(' '));
const handleTriggerClick = () => {
isOpened.value = !isOpened.value;
rootMenu.handleSubMenuExpand(subMenu, indexPath);
};
watch([rootMenu.currentExpandedKeys], () => {
// 要通过监听 currentExpandedKeys,自动打开或者关闭子菜单
const currentIsExpanded = rootMenu.currentExpandedKeys.value.includes(props.value || instance.uid);
if (isOpened.value && !currentIsExpanded) {
isOpened.value = false;
} else if (!isOpened.value && currentIsExpanded) {
isOpened.value = true;
}
}, {
immediate: true
});
const renderTitle = () => {
var _slots$label;
return createVNode(Ellipsis, {
"class": `${prefixCls}-label`
}, {
default: () => [((_slots$label = slots.label) === null || _slots$label === void 0 ? void 0 : _slots$label.call(slots)) || props.label]
});
};
const renderIcon = () => {
if (slots.icon) {
return createVNode("div", {
"class": `${prefixCls}-icon`
}, [slots.icon()]);
}
if (onlyIcon.value) {
return renderTitle();
}
return null;
};
const renderArrow = () => {
if (rootMenu.renderWithPopper.value && !isFirstLevel.value) {
return createVNode("span", {
"class": `${prefixCls}-arrow`
}, [createVNode(RightOutlined, null, null)]);
}
return createVNode("span", {
"class": [`${prefixCls}-arrow`, isOpened.value && 'is-opened']
}, [createVNode(DownOutlined, null, null)]);
};
const wrapperContent = () => {
return createVNode(Fragment, null, [renderIcon(), !onlyIcon.value ? renderTitle() : null, !onlyIcon.value ? renderArrow() : null]);
};
const renderWrapperClick = () => {
return createVNode("div", {
"class": `${prefixCls}-wrapper`,
"style": paddingStyle.value,
"onClick": handleTriggerClick
}, [wrapperContent()]);
};
const renderWrapperPopper = () => {
return createVNode("div", {
"class": `${prefixCls}-wrapper`,
"style": paddingStyle.value
}, [wrapperContent()]);
};
const renderDefault = () => {
var _slots$default;
return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots);
};
const popperProps = computed(() => {
if (!rootMenu.renderWithPopper.value) {
return {};
}
return pick(rootMenu.props, ['getContainer', 'appendToContainer']);
});
const renderContent = () => {
if (rootMenu.renderWithPopper.value) {
return createVNode(Popper, mergeProps({
"modelValue": isOpened.value,
"onUpdate:modelValue": $event => isOpened.value = $event
}, popperProps.value, {
"trigger": `hover`,
"placement": placement.value,
"popperClass": `${prefixCls}-popper`,
"appendToContainer": !(indexPath.value.length > 2),
"offset": 1
}), {
default: renderDefault,
trigger: () => renderWrapperPopper()
});
}
return createVNode(Fragment, null, [renderWrapperClick(), createVNode(FadeInExpandTransition, null, {
default: () => [withDirectives(createVNode("div", {
"class": `${prefixCls}-children`
}, [renderDefault()]), [[vShow, isOpened.value]])]
})]);
};
return () => createVNode("div", {
"class": classList.value,
"ref": subMenuRef
}, [renderContent()]);
}
});
export { subMenu as default, subMenuProps };