ant-design-vue/components/vc-dropdown/src/Dropdown.jsx

212 lines
5.9 KiB
Vue
Raw Normal View History

2019-03-02 04:53:22 +00:00
import classNames from 'classnames';
2019-01-12 03:33:27 +00:00
import PropTypes from '../../_util/vue-types';
import Trigger from '../../vc-trigger';
import placements from './placements';
import { hasProp, getEvents, getOptionProps } from '../../_util/props-util';
import BaseMixin from '../../_util/BaseMixin';
import { cloneElement } from '../../_util/vnode';
2018-01-29 10:57:20 +00:00
export default {
mixins: [BaseMixin],
props: {
minOverlayWidthMatchTrigger: PropTypes.bool.def(true),
prefixCls: PropTypes.string.def('rc-dropdown'),
transitionName: PropTypes.string,
overlayClassName: PropTypes.string.def(''),
2019-03-02 04:53:22 +00:00
openClassName: PropTypes.string,
2018-01-29 10:57:20 +00:00
animation: PropTypes.any,
align: PropTypes.object,
overlayStyle: PropTypes.object.def({}),
placement: PropTypes.string.def('bottomLeft'),
2019-03-02 04:53:22 +00:00
overlay: PropTypes.oneOfType([
PropTypes.any,
PropTypes.func,
]),
2018-01-29 10:57:20 +00:00
trigger: PropTypes.array.def(['hover']),
2018-10-30 13:10:00 +00:00
alignPoint: PropTypes.bool,
2018-01-29 10:57:20 +00:00
showAction: PropTypes.array.def([]),
hideAction: PropTypes.array.def([]),
getPopupContainer: PropTypes.func,
visible: PropTypes.bool,
defaultVisible: PropTypes.bool.def(false),
mouseEnterDelay: PropTypes.number.def(0.15),
mouseLeaveDelay: PropTypes.number.def(0.1),
},
2019-01-12 03:33:27 +00:00
data() {
let sVisible = this.defaultVisible;
2018-01-29 10:57:20 +00:00
if (hasProp(this, 'visible')) {
2019-01-12 03:33:27 +00:00
sVisible = this.visible;
2018-01-29 10:57:20 +00:00
}
return {
sVisible,
2019-01-12 03:33:27 +00:00
};
2018-01-29 10:57:20 +00:00
},
watch: {
2019-01-12 03:33:27 +00:00
visible(val) {
2018-01-29 10:57:20 +00:00
if (val !== undefined) {
this.setState({
sVisible: val,
2019-01-12 03:33:27 +00:00
});
2018-01-29 10:57:20 +00:00
}
},
},
methods: {
2019-01-12 03:33:27 +00:00
onClick(e) {
2018-01-29 10:57:20 +00:00
// do no call onVisibleChange, if you need click to hide, use onClick and control visible
if (!hasProp(this, 'visible')) {
this.setState({
sVisible: false,
2019-01-12 03:33:27 +00:00
});
2018-01-29 10:57:20 +00:00
}
2019-01-12 03:33:27 +00:00
this.$emit('overlayClick', e);
2018-01-29 10:57:20 +00:00
if (this.childOriginEvents.click) {
2019-01-12 03:33:27 +00:00
this.childOriginEvents.click(e);
2018-01-29 10:57:20 +00:00
}
},
2019-01-12 03:33:27 +00:00
onVisibleChange(visible) {
2018-01-29 10:57:20 +00:00
if (!hasProp(this, 'visible')) {
this.setState({
sVisible: visible,
2019-01-12 03:33:27 +00:00
});
2018-01-29 10:57:20 +00:00
}
2019-01-12 03:33:27 +00:00
this.__emit('visibleChange', visible);
2018-01-29 10:57:20 +00:00
},
2019-01-12 03:33:27 +00:00
getMinOverlayWidthMatchTrigger() {
const props = getOptionProps(this);
const { minOverlayWidthMatchTrigger, alignPoint } = props;
2018-10-30 13:10:00 +00:00
if ('minOverlayWidthMatchTrigger' in props) {
2019-01-12 03:33:27 +00:00
return minOverlayWidthMatchTrigger;
2018-10-30 13:10:00 +00:00
}
2019-01-12 03:33:27 +00:00
return !alignPoint;
2018-10-30 13:10:00 +00:00
},
2019-03-02 04:53:22 +00:00
getOverlayElement() {
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
let overlayElement;
if (typeof overlay === 'function') {
overlayElement = overlay();
} else {
overlayElement = overlay;
}
return overlayElement;
},
2019-01-12 03:33:27 +00:00
getMenuElement() {
const { onClick, prefixCls, $slots } = this;
this.childOriginEvents = getEvents($slots.overlay[0]);
2019-03-02 04:53:22 +00:00
const overlayElement = this.getOverlayElement();
2018-04-03 06:34:54 +00:00
const extraOverlayProps = {
2018-02-05 03:18:50 +00:00
props: {
prefixCls: `${prefixCls}-menu`,
2018-04-03 06:34:54 +00:00
getPopupContainer: () => this.getPopupDomNode(),
2018-02-05 03:18:50 +00:00
},
2018-01-29 10:57:20 +00:00
on: {
2018-02-05 03:18:50 +00:00
click: onClick,
2018-01-29 10:57:20 +00:00
},
2019-01-12 03:33:27 +00:00
};
2019-03-02 04:53:22 +00:00
if (typeof overlayElement.type === 'string') {
delete extraOverlayProps.props.prefixCls;
}
2019-01-12 03:33:27 +00:00
return cloneElement($slots.overlay[0], extraOverlayProps);
2018-01-29 10:57:20 +00:00
},
2019-03-02 04:53:22 +00:00
getMenuElementOrLambda() {
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
if (typeof overlay === 'function') {
return this.getMenuElement;
}
return this.getMenuElement();
},
2019-01-12 03:33:27 +00:00
getPopupDomNode() {
return this.$refs.trigger.getPopupDomNode();
2018-01-29 10:57:20 +00:00
},
2019-03-02 04:53:22 +00:00
getOpenClassName() {
const { openClassName, prefixCls } = this.$props;
if (openClassName !== undefined) {
return openClassName;
}
return `${prefixCls}-open`;
},
2019-01-12 03:33:27 +00:00
afterVisibleChange(visible) {
2018-10-30 13:10:00 +00:00
if (visible && this.getMinOverlayWidthMatchTrigger()) {
2019-01-12 03:33:27 +00:00
const overlayNode = this.getPopupDomNode();
const rootNode = this.$el;
2018-01-29 10:57:20 +00:00
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) {
2019-01-12 03:33:27 +00:00
overlayNode.style.minWidth = `${rootNode.offsetWidth}px`;
if (
this.$refs.trigger &&
2018-01-29 10:57:20 +00:00
this.$refs.trigger._component &&
2019-01-12 03:33:27 +00:00
this.$refs.trigger._component.alignInstance
) {
this.$refs.trigger._component.alignInstance.forceAlign();
2018-01-29 10:57:20 +00:00
}
}
}
},
2019-03-02 04:53:22 +00:00
renderChildren() {
const children = this.$slots.default && this.$slots.default[0];
const { sVisible } = this;
return (sVisible && children) ? cloneElement(children, { class: this.getOpenClassName() }) : children;
},
2018-01-29 10:57:20 +00:00
},
2019-01-12 03:33:27 +00:00
render() {
2018-01-29 10:57:20 +00:00
const {
prefixCls,
2019-01-12 03:33:27 +00:00
transitionName,
animation,
align,
placement,
getPopupContainer,
showAction,
hideAction,
overlayClassName,
overlayStyle,
trigger,
...otherProps
} = this.$props;
let triggerHideAction = hideAction;
2018-10-30 13:10:00 +00:00
if (!triggerHideAction && trigger.indexOf('contextmenu') !== -1) {
2019-01-12 03:33:27 +00:00
triggerHideAction = ['click'];
2018-10-30 13:10:00 +00:00
}
2018-01-29 10:57:20 +00:00
const triggerProps = {
props: {
...otherProps,
prefixCls,
popupClassName: overlayClassName,
popupStyle: overlayStyle,
builtinPlacements: placements,
action: trigger,
showAction,
2018-10-30 13:10:00 +00:00
hideAction: triggerHideAction || [],
2018-01-29 10:57:20 +00:00
popupPlacement: placement,
popupAlign: align,
popupTransitionName: transitionName,
popupAnimation: animation,
popupVisible: this.sVisible,
afterPopupVisibleChange: this.afterVisibleChange,
getPopupContainer: getPopupContainer,
},
on: {
popupVisibleChange: this.onVisibleChange,
},
ref: 'trigger',
2019-01-12 03:33:27 +00:00
};
const child = this.$slots.default && this.$slots.default[0];
2018-01-29 10:57:20 +00:00
return (
<Trigger {...triggerProps}>
2019-03-02 04:53:22 +00:00
{this.renderChildren()}
2019-01-12 03:33:27 +00:00
<template slot="popup">{this.$slots.overlay && this.getMenuElement()}</template>
2018-01-29 10:57:20 +00:00
</Trigger>
2019-01-12 03:33:27 +00:00
);
2018-01-29 10:57:20 +00:00
},
2019-01-12 03:33:27 +00:00
};