mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-15 17:31:43 +08:00
73bef787cd
* feat: add Result component * fix: update md template tag html>tpl - fix `result` typo - update jest `result` snapshots * refactor: svg file to functional component icon - update jest snapshot * feat: add result * Feat descriptions (#1251) * feat: add descriptions * fix: add descriptions types and fix docs * fix: lint change code * fix: demo warning * fix: update demo, snapshot and remove classnames * test: add descriptions test * fix: descriptions demo (#1498) * feat: add page header (#1250) * feat: add page-header component * update site: page-header * ts definition update: page-header * get page-header props with getComponentFromProp func * optimize page-header * doc: add page-header actions.md responsive.md * breadcrumb itemRender add pure function support * style: format code * feat: update style to 3.23.6 from 2.13.6 * feat: update style to 3.26.8 from 3.23.6 * chore: update util * chore: update util * feat: update affix * feat: update alert * feat: update anchor * feat: update auto-complete * feat: update avatar * feat: update back-top * feat: update badge * feat: update button * feat: update breadcrumb * feat: update ts * docs: update doc * feat: update calendat * feat: update card * feat: update carousel * feat: update carousel * feat: update checkbox * feat: update comment * feat: update config-provider * docs: update doc * feat: update collapse * feat: update locale * feat: update date-picker * feat: update divider * feat: update drawer * feat: update dropdown * feat: update rc-trigger * feat: update dropdown * feat: update empty * test: add empty test * feat: update form * feat: update form * feat: update spin * feat: update grid * docs: update grid doc * feat: update icon * feat: update slider * feat: update textarea * feat: update input-number * feat: update layout * feat: update list * feat: update menu * feat: meaage add key for update content * feat: modal add closeIcon support * feat: update notification * feat: add pagination disabled support * feat: popconfirm add disabled support * test: update popover * feat: progress support custom line-gradiend * feat: update radio * test: update radio test * docs: update rate demo * feat: skeleton add avatar support number type * test: add switch test * test: update statistic test * fix: input clear icon event * feat: steps add type、 v-model、subTitle * feat: delete typography component * feat: delete Typography style * perf: update select * feat: add download transformFile previewFile actio * docs: update upload * feat: update tree-select * docs: update tree-select * feat: tree add blockNode selectable * docs: add tree demo * test: update snap * docs: updatedoc * feat: update tag * docs: update ad doc * feat: update tooltip * feat: update timeline * feat: time-picker add clearIcon * docs: update tabs * feat: transfer support custom children * test: update transfer test * feat: update table * test: update table test * test: update test * feat: calendar update locale * test: update test snap * feat: add mentions (#1790) * feat: mentions style * feat: theme default * feat: add mentions component * feat: mentions API * feat: add unit test for mentions * feat: update mentions demo * perf: model and inheritAttrs for mentions * perf: use getComponentFromProp instead of this.$props * perf: mentions rm defaultProps * feat: rm rows in mentionsProps * fix: mentions keyDown didn't work * docs: update mentions api * perf: mentions code * feat: update mentions * bump 1.5.0-alpha.1 * feat: pageheader add ghost prop * docs: update descriptions demo * chore: page-header add ghost type * fix: color error * feat: update to 3.26.12 * fix: some prop default value * fix(typo): form, carousel, upload. duplicate identifier (#1848) * Add Mentions Type (#1845) * feat: add mentions type * feat: add mentions in ant-design-vue.d.ts * docs: update doc * docs: add changelog * fix: mentions getPopupCotainer value (#1850) * docs: update doc * docs: uptate demo * docs: update demo * docs: delete demo * docs: delete doc * test: update snapshots * style: format code * chore: update travis * docs: update demo Co-authored-by: Sendya <18x@loacg.com> Co-authored-by: zkwolf <chenhao5866@gmail.com> Co-authored-by: drafish <xwlyy1991@163.com> Co-authored-by: Amour1688 <31695475+Amour1688@users.noreply.github.com>
333 lines
9.6 KiB
Vue
333 lines
9.6 KiB
Vue
import PropTypes from '../_util/vue-types';
|
||
import Align from '../vc-align';
|
||
import PopupInner from './PopupInner';
|
||
import LazyRenderBox from './LazyRenderBox';
|
||
import animate from '../_util/css-animation';
|
||
import BaseMixin from '../_util/BaseMixin';
|
||
import { getListeners } from '../_util/props-util';
|
||
|
||
export default {
|
||
name: 'VCTriggerPopup',
|
||
mixins: [BaseMixin],
|
||
props: {
|
||
visible: PropTypes.bool,
|
||
getClassNameFromAlign: PropTypes.func,
|
||
getRootDomNode: PropTypes.func,
|
||
align: PropTypes.any,
|
||
destroyPopupOnHide: PropTypes.bool,
|
||
prefixCls: PropTypes.string,
|
||
getContainer: PropTypes.func,
|
||
transitionName: PropTypes.string,
|
||
animation: PropTypes.any,
|
||
maskAnimation: PropTypes.string,
|
||
maskTransitionName: PropTypes.string,
|
||
mask: PropTypes.bool,
|
||
zIndex: PropTypes.number,
|
||
popupClassName: PropTypes.any,
|
||
popupStyle: PropTypes.object.def(() => ({})),
|
||
stretch: PropTypes.string,
|
||
point: PropTypes.shape({
|
||
pageX: PropTypes.number,
|
||
pageY: PropTypes.number,
|
||
}),
|
||
},
|
||
data() {
|
||
this.domEl = null;
|
||
return {
|
||
// Used for stretch
|
||
stretchChecked: false,
|
||
targetWidth: undefined,
|
||
targetHeight: undefined,
|
||
};
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
this.rootNode = this.getPopupDomNode();
|
||
this.setStretchSize();
|
||
});
|
||
},
|
||
beforeUpdate() {
|
||
if (this.domEl && this.domEl.rcEndListener) {
|
||
this.domEl.rcEndListener();
|
||
this.domEl = null;
|
||
}
|
||
},
|
||
updated() {
|
||
this.$nextTick(() => {
|
||
this.setStretchSize();
|
||
});
|
||
},
|
||
beforeDestroy() {
|
||
if (this.$el.parentNode) {
|
||
this.$el.parentNode.removeChild(this.$el);
|
||
} else if (this.$el.remove) {
|
||
this.$el.remove();
|
||
}
|
||
},
|
||
methods: {
|
||
onAlign(popupDomNode, align) {
|
||
const props = this.$props;
|
||
const currentAlignClassName = props.getClassNameFromAlign(align);
|
||
// FIX: https://github.com/react-component/trigger/issues/56
|
||
// FIX: https://github.com/react-component/tooltip/issues/79
|
||
if (this.currentAlignClassName !== currentAlignClassName) {
|
||
this.currentAlignClassName = currentAlignClassName;
|
||
popupDomNode.className = this.getClassName(currentAlignClassName);
|
||
}
|
||
const listeners = getListeners(this);
|
||
listeners.align && listeners.align(popupDomNode, align);
|
||
},
|
||
|
||
// Record size if stretch needed
|
||
setStretchSize() {
|
||
const { stretch, getRootDomNode, visible } = this.$props;
|
||
const { stretchChecked, targetHeight, targetWidth } = this.$data;
|
||
|
||
if (!stretch || !visible) {
|
||
if (stretchChecked) {
|
||
this.setState({ stretchChecked: false });
|
||
}
|
||
return;
|
||
}
|
||
|
||
const $ele = getRootDomNode();
|
||
if (!$ele) return;
|
||
|
||
const height = $ele.offsetHeight;
|
||
const width = $ele.offsetWidth;
|
||
|
||
if (targetHeight !== height || targetWidth !== width || !stretchChecked) {
|
||
this.setState({
|
||
stretchChecked: true,
|
||
targetHeight: height,
|
||
targetWidth: width,
|
||
});
|
||
}
|
||
},
|
||
|
||
getPopupDomNode() {
|
||
return this.$refs.popupInstance ? this.$refs.popupInstance.$el : null;
|
||
},
|
||
|
||
getTargetElement() {
|
||
return this.$props.getRootDomNode();
|
||
},
|
||
|
||
// `target` on `rc-align` can accept as a function to get the bind element or a point.
|
||
// ref: https://www.npmjs.com/package/rc-align
|
||
getAlignTarget() {
|
||
const { point } = this.$props;
|
||
if (point) {
|
||
return point;
|
||
}
|
||
return this.getTargetElement;
|
||
},
|
||
|
||
getMaskTransitionName() {
|
||
const props = this.$props;
|
||
let transitionName = props.maskTransitionName;
|
||
const animation = props.maskAnimation;
|
||
if (!transitionName && animation) {
|
||
transitionName = `${props.prefixCls}-${animation}`;
|
||
}
|
||
return transitionName;
|
||
},
|
||
|
||
getTransitionName() {
|
||
const props = this.$props;
|
||
let transitionName = props.transitionName;
|
||
const animation = props.animation;
|
||
if (!transitionName) {
|
||
if (typeof animation === 'string') {
|
||
transitionName = `${animation}`;
|
||
} else if (animation && animation.props && animation.props.name) {
|
||
transitionName = animation.props.name;
|
||
}
|
||
}
|
||
return transitionName;
|
||
},
|
||
|
||
getClassName(currentAlignClassName) {
|
||
return `${this.$props.prefixCls} ${this.$props.popupClassName} ${currentAlignClassName}`;
|
||
},
|
||
getPopupElement() {
|
||
const { $props: props, $slots, getTransitionName } = this;
|
||
const { stretchChecked, targetHeight, targetWidth } = this.$data;
|
||
|
||
const {
|
||
align,
|
||
visible,
|
||
prefixCls,
|
||
animation,
|
||
popupStyle,
|
||
getClassNameFromAlign,
|
||
destroyPopupOnHide,
|
||
stretch,
|
||
} = props;
|
||
const className = this.getClassName(
|
||
this.currentAlignClassName || getClassNameFromAlign(align),
|
||
);
|
||
// const hiddenClassName = `${prefixCls}-hidden`
|
||
if (!visible) {
|
||
this.currentAlignClassName = null;
|
||
}
|
||
const sizeStyle = {};
|
||
if (stretch) {
|
||
// Stretch with target
|
||
if (stretch.indexOf('height') !== -1) {
|
||
sizeStyle.height = typeof targetHeight === 'number' ? `${targetHeight}px` : targetHeight;
|
||
} else if (stretch.indexOf('minHeight') !== -1) {
|
||
sizeStyle.minHeight =
|
||
typeof targetHeight === 'number' ? `${targetHeight}px` : targetHeight;
|
||
}
|
||
if (stretch.indexOf('width') !== -1) {
|
||
sizeStyle.width = typeof targetWidth === 'number' ? `${targetWidth}px` : targetWidth;
|
||
} else if (stretch.indexOf('minWidth') !== -1) {
|
||
sizeStyle.minWidth = typeof targetWidth === 'number' ? `${targetWidth}px` : targetWidth;
|
||
}
|
||
// Delay force align to makes ui smooth
|
||
if (!stretchChecked) {
|
||
// sizeStyle.visibility = 'hidden'
|
||
setTimeout(() => {
|
||
if (this.$refs.alignInstance) {
|
||
this.$refs.alignInstance.forceAlign();
|
||
}
|
||
}, 0);
|
||
}
|
||
}
|
||
const popupInnerProps = {
|
||
props: {
|
||
prefixCls,
|
||
visible,
|
||
// hiddenClassName,
|
||
},
|
||
class: className,
|
||
on: getListeners(this),
|
||
ref: 'popupInstance',
|
||
style: { ...sizeStyle, ...popupStyle, ...this.getZIndexStyle() },
|
||
};
|
||
let transitionProps = {
|
||
props: Object.assign({
|
||
appear: true,
|
||
css: false,
|
||
}),
|
||
};
|
||
const transitionName = getTransitionName();
|
||
let useTransition = !!transitionName;
|
||
const transitionEvent = {
|
||
beforeEnter: () => {
|
||
// el.style.display = el.__vOriginalDisplay
|
||
// this.$refs.alignInstance.forceAlign();
|
||
},
|
||
enter: (el, done) => {
|
||
// render 后 vue 会移除通过animate动态添加的 class导致动画闪动,延迟两帧添加动画class,可以进一步定位或者重写 transition 组件
|
||
this.$nextTick(() => {
|
||
if (this.$refs.alignInstance) {
|
||
this.$refs.alignInstance.$nextTick(() => {
|
||
this.domEl = el;
|
||
animate(el, `${transitionName}-enter`, done);
|
||
});
|
||
}
|
||
});
|
||
},
|
||
beforeLeave: () => {
|
||
this.domEl = null;
|
||
},
|
||
leave: (el, done) => {
|
||
animate(el, `${transitionName}-leave`, done);
|
||
},
|
||
};
|
||
|
||
if (typeof animation === 'object') {
|
||
useTransition = true;
|
||
const { on = {}, props = {} } = animation;
|
||
transitionProps.props = { ...transitionProps.props, ...props };
|
||
transitionProps.on = { ...transitionEvent, ...on };
|
||
} else {
|
||
transitionProps.on = transitionEvent;
|
||
}
|
||
if (!useTransition) {
|
||
transitionProps = {};
|
||
}
|
||
if (destroyPopupOnHide) {
|
||
return (
|
||
<transition {...transitionProps}>
|
||
{visible ? (
|
||
<Align
|
||
target={this.getAlignTarget()}
|
||
key="popup"
|
||
ref="alignInstance"
|
||
monitorWindowResize
|
||
align={align}
|
||
onAlign={this.onAlign}
|
||
>
|
||
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
|
||
</Align>
|
||
) : null}
|
||
</transition>
|
||
);
|
||
}
|
||
return (
|
||
<transition {...transitionProps}>
|
||
<Align
|
||
v-show={visible}
|
||
target={this.getAlignTarget()}
|
||
key="popup"
|
||
ref="alignInstance"
|
||
monitorWindowResize
|
||
disabled={!visible}
|
||
align={align}
|
||
onAlign={this.onAlign}
|
||
>
|
||
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
|
||
</Align>
|
||
</transition>
|
||
);
|
||
},
|
||
|
||
getZIndexStyle() {
|
||
const style = {};
|
||
const props = this.$props;
|
||
if (props.zIndex !== undefined) {
|
||
style.zIndex = props.zIndex;
|
||
}
|
||
return style;
|
||
},
|
||
|
||
getMaskElement() {
|
||
const props = this.$props;
|
||
let maskElement = null;
|
||
if (props.mask) {
|
||
const maskTransition = this.getMaskTransitionName();
|
||
maskElement = (
|
||
<LazyRenderBox
|
||
v-show={props.visible}
|
||
style={this.getZIndexStyle()}
|
||
key="mask"
|
||
class={`${props.prefixCls}-mask`}
|
||
visible={props.visible}
|
||
/>
|
||
);
|
||
if (maskTransition) {
|
||
maskElement = (
|
||
<transition appear name={maskTransition}>
|
||
{maskElement}
|
||
</transition>
|
||
);
|
||
}
|
||
}
|
||
return maskElement;
|
||
},
|
||
},
|
||
|
||
render() {
|
||
const { getMaskElement, getPopupElement } = this;
|
||
return (
|
||
<div>
|
||
{getMaskElement()}
|
||
{getPopupElement()}
|
||
</div>
|
||
);
|
||
},
|
||
};
|