From a0e637da9c3c95fa73fd68ede26f8dc7f8e941f9 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Sun, 21 Jun 2020 22:45:30 +0800
Subject: [PATCH] feat: update dropdown
---
antdv-demo | 2 +-
breakChange-2.x.md | 4 ++
components/_util/props-util.js | 3 +-
components/dropdown/dropdown-button.jsx | 45 +++++-------
components/dropdown/dropdown.jsx | 73 ++++++++-----------
components/vc-align/Align.jsx | 9 ++-
components/vc-dropdown/src/Dropdown.jsx | 96 +++++++++++--------------
components/vc-trigger/LazyRenderBox.jsx | 7 +-
examples/index.js | 2 +
9 files changed, 110 insertions(+), 131 deletions(-)
diff --git a/antdv-demo b/antdv-demo
index 78341d7cd..bf1777054 160000
--- a/antdv-demo
+++ b/antdv-demo
@@ -1 +1 @@
-Subproject commit 78341d7cd7c34015b7369982cfa7914fbc558232
+Subproject commit bf1777054fbe55a0d3bbdd037573e3a235137fbb
diff --git a/breakChange-2.x.md b/breakChange-2.x.md
index 83c852871..91ca89edb 100644
--- a/breakChange-2.x.md
+++ b/breakChange-2.x.md
@@ -43,3 +43,7 @@ v-model -> v-model:value
## menu
v-model -> v-model:selectedKeys :openKeys.sync -> v-mdoel:openKeys
+
+## dropdown
+
+v-model -> v-model:visible
diff --git a/components/_util/props-util.js b/components/_util/props-util.js
index ccec0fa7f..5ea7f004c 100644
--- a/components/_util/props-util.js
+++ b/components/_util/props-util.js
@@ -200,7 +200,6 @@ const getAllProps = ele => {
return props;
};
-// 使用 getOptionProps 替换 ,待测试
const getPropsData = vnode => {
const res = {};
const originProps = vnode.props || {};
@@ -208,7 +207,7 @@ const getPropsData = vnode => {
Object.keys(originProps).forEach(key => {
props[camelize(key)] = originProps[key];
});
- const options = vnode.type.props;
+ const options = isPlainObject(vnode.type) ? vnode.type.props : {};
Object.keys(options).forEach(k => {
const v = resolvePropValue(options, props, k, props[k]);
if (k in props) {
diff --git a/components/dropdown/dropdown-button.jsx b/components/dropdown/dropdown-button.jsx
index d5b21a13c..c587629e1 100644
--- a/components/dropdown/dropdown-button.jsx
+++ b/components/dropdown/dropdown-button.jsx
@@ -1,9 +1,10 @@
+import { provide, inject } from 'vue';
import Button from '../button';
import buttonTypes from '../button/buttonTypes';
import { ButtonGroupProps } from '../button/button-group';
import Dropdown from './dropdown';
import PropTypes from '../_util/vue-types';
-import { hasProp, getComponentFromProp } from '../_util/props-util';
+import { hasProp, getComponent, getSlot } from '../_util/props-util';
import getDropdownProps from './getDropdownProps';
import { ConfigConsumerProps } from '../config-provider';
import EllipsisOutlined from '@ant-design/icons-vue/EllipsisOutlined';
@@ -27,18 +28,14 @@ const DropdownButtonProps = {
export { DropdownButtonProps };
export default {
name: 'ADropdownButton',
- model: {
- prop: 'visible',
- event: 'visibleChange',
- },
props: DropdownButtonProps,
- provide() {
+ setup() {
return {
- savePopupRef: this.savePopupRef,
+ configProvider: inject('configProvider', ConfigConsumerProps),
};
},
- inject: {
- configProvider: { default: () => ConfigConsumerProps },
+ created() {
+ provide('savePopupRef', this.savePopupRef);
},
methods: {
savePopupRef(ref) {
@@ -48,6 +45,7 @@ export default {
this.$emit('click', e);
},
onVisibleChange(val) {
+ this.$emit('update:visible', val);
this.$emit('visibleChange', val);
},
},
@@ -66,30 +64,24 @@ export default {
title,
...restProps
} = this.$props;
- const icon = getComponentFromProp(this, 'icon') || ;
+ const icon = getComponent(this, 'icon') || ;
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('dropdown-button', customizePrefixCls);
const dropdownProps = {
- props: {
- align,
- disabled,
- trigger: disabled ? [] : trigger,
- placement,
- getPopupContainer: getPopupContainer || getContextPopupContainer,
- },
- on: {
- visibleChange: this.onVisibleChange,
- },
+ align,
+ disabled,
+ trigger: disabled ? [] : trigger,
+ placement,
+ getPopupContainer: getPopupContainer || getContextPopupContainer,
+ onVisibleChange: this.onVisibleChange,
};
if (hasProp(this, 'visible')) {
- dropdownProps.props.visible = visible;
+ dropdownProps.visible = visible;
}
const buttonGroupProps = {
- props: {
- ...restProps,
- },
+ ...restProps,
class: prefixCls,
};
@@ -103,10 +95,9 @@ export default {
href={href}
title={title}
>
- {this.$slots.default}
+ {getSlot(this)}
-
- {getComponentFromProp(this, 'overlay')}
+
diff --git a/components/dropdown/dropdown.jsx b/components/dropdown/dropdown.jsx
index eb6a3bf69..957525692 100644
--- a/components/dropdown/dropdown.jsx
+++ b/components/dropdown/dropdown.jsx
@@ -1,3 +1,4 @@
+import { provide, inject, cloneVNode } from 'vue';
import RcDropdown from '../vc-dropdown/src/index';
import DropdownButton from './dropdown-button';
import PropTypes from '../_util/vue-types';
@@ -5,8 +6,9 @@ import { cloneElement } from '../_util/vnode';
import {
getOptionProps,
getPropsData,
- getComponentFromProp,
- getListeners,
+ getComponent,
+ isValidElement,
+ getSlot,
} from '../_util/props-util';
import getDropdownProps from './getDropdownProps';
import { ConfigConsumerProps } from '../config-provider';
@@ -22,17 +24,13 @@ const Dropdown = {
mouseLeaveDelay: PropTypes.number.def(0.1),
placement: DropdownProps.placement.def('bottomLeft'),
},
- model: {
- prop: 'visible',
- event: 'visibleChange',
- },
- provide() {
+ setup() {
return {
- savePopupRef: this.savePopupRef,
+ configProvider: inject('configProvider', ConfigConsumerProps),
};
},
- inject: {
- configProvider: { default: () => ConfigConsumerProps },
+ created() {
+ provide('savePopupRef', this.savePopupRef);
},
methods: {
savePopupRef(ref) {
@@ -49,7 +47,7 @@ const Dropdown = {
return 'slide-up';
},
renderOverlay(prefixCls) {
- const overlay = getComponentFromProp(this, 'overlay');
+ const overlay = getComponent(this, 'overlay');
const overlayNode = Array.isArray(overlay) ? overlay[0] : overlay;
// menu cannot be selectable in dropdown defaultly
// menu should be focusable in dropdown defaultly
@@ -61,57 +59,48 @@ const Dropdown = {
);
- const fixedModeOverlay =
- overlayNode && overlayNode.componentOptions
- ? cloneElement(overlayNode, {
- props: {
- mode: 'vertical',
- selectable,
- focusable,
- expandIcon,
- },
- })
- : overlay;
+ const fixedModeOverlay = isValidElement(overlayNode)
+ ? cloneVNode(overlayNode, {
+ mode: 'vertical',
+ selectable,
+ focusable,
+ expandIcon,
+ })
+ : overlay;
return fixedModeOverlay;
},
},
render() {
- const { $slots } = this;
const props = getOptionProps(this);
const { prefixCls: customizePrefixCls, trigger, disabled, getPopupContainer } = props;
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
- const dropdownTrigger = cloneElement($slots.default, {
- class: `${prefixCls}-trigger`,
- props: {
+ const dropdownTrigger = cloneElement(
+ getSlot(this),
+ {
+ class: `${prefixCls}-trigger`,
disabled,
},
- });
+ false,
+ );
const triggerActions = disabled ? [] : trigger;
let alignPoint;
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
alignPoint = true;
}
const dropdownProps = {
- props: {
- alignPoint,
- ...props,
- prefixCls,
- getPopupContainer: getPopupContainer || getContextPopupContainer,
- transitionName: this.getTransitionName(),
- trigger: triggerActions,
- },
- on: getListeners(this),
+ alignPoint,
+ ...props,
+ prefixCls,
+ getPopupContainer: getPopupContainer || getContextPopupContainer,
+ transitionName: this.getTransitionName(),
+ trigger: triggerActions,
+ overlay: this.renderOverlay(prefixCls),
};
- return (
-
- {dropdownTrigger}
- {this.renderOverlay(prefixCls)}
-
- );
+ return {dropdownTrigger};
},
};
diff --git a/components/vc-align/Align.jsx b/components/vc-align/Align.jsx
index 942db23e3..719d0cf81 100644
--- a/components/vc-align/Align.jsx
+++ b/components/vc-align/Align.jsx
@@ -5,7 +5,7 @@ import addEventListener from '../vc-util/Dom/addEventListener';
import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
import { cloneElement } from '../_util/vnode.js';
import clonedeep from 'lodash/cloneDeep';
-import { getSlot, getListeners } from '../_util/props-util';
+import { getSlot, findDOMNode } from '../_util/props-util';
function getElement(func) {
if (typeof func !== 'function' || !func) return null;
@@ -117,8 +117,7 @@ export default {
forceAlign() {
const { disabled, target, align } = this.$props;
if (!disabled && target) {
- const source = this.$el;
- const listeners = getListeners(this);
+ const source = findDOMNode(this);
let result;
const element = getElement(target);
const point = getPoint(target);
@@ -134,7 +133,7 @@ export default {
}
restoreFocus(activeElement, source);
this.aligned = true;
- listeners.align && listeners.align(source, result);
+ this.$attrs.onAlign && this.$attrs.onAlign(source, result);
}
},
},
@@ -143,7 +142,7 @@ export default {
const { childrenProps } = this.$props;
const child = getSlot(this);
if (child && childrenProps) {
- return cloneElement(child[0], { props: childrenProps });
+ return cloneElement(child[0], childrenProps);
}
return child && child[0];
},
diff --git a/components/vc-dropdown/src/Dropdown.jsx b/components/vc-dropdown/src/Dropdown.jsx
index fe28e6cc3..08effac34 100644
--- a/components/vc-dropdown/src/Dropdown.jsx
+++ b/components/vc-dropdown/src/Dropdown.jsx
@@ -1,7 +1,14 @@
+import { Text } from 'vue';
import PropTypes from '../../_util/vue-types';
import Trigger from '../../vc-trigger';
import placements from './placements';
-import { hasProp, getEvents, getOptionProps } from '../../_util/props-util';
+import {
+ hasProp,
+ getComponent,
+ getOptionProps,
+ getSlot,
+ findDOMNode,
+} from '../../_util/props-util';
import BaseMixin from '../../_util/BaseMixin';
import { cloneElement } from '../../_util/vnode';
@@ -48,6 +55,7 @@ export default {
},
methods: {
onClick(e) {
+ const overlayProps = this.getOverlayElement().props;
// do no call onVisibleChange, if you need click to hide, use onClick and control visible
if (!hasProp(this, 'visible')) {
this.setState({
@@ -55,8 +63,8 @@ export default {
});
}
this.$emit('overlayClick', e);
- if (this.childOriginEvents.click) {
- this.childOriginEvents.click(e);
+ if (overlayProps.onClick) {
+ overlayProps.onClick(e);
}
},
@@ -66,6 +74,7 @@ export default {
sVisible: visible,
});
}
+ this.$emit('update:visible', visible);
this.__emit('visibleChange', visible);
},
@@ -80,37 +89,26 @@ export default {
},
getOverlayElement() {
- const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
- let overlayElement;
- if (typeof overlay === 'function') {
- overlayElement = overlay();
- } else {
- overlayElement = overlay;
- }
- return overlayElement;
+ const overlay = getComponent(this, 'overlay');
+ return Array.isArray(overlay) ? overlay[0] : overlay;
},
getMenuElement() {
- const { onClick, prefixCls, $slots } = this;
- this.childOriginEvents = getEvents($slots.overlay[0]);
+ const { onClick, prefixCls } = this;
const overlayElement = this.getOverlayElement();
const extraOverlayProps = {
- props: {
- prefixCls: `${prefixCls}-menu`,
- getPopupContainer: () => this.getPopupDomNode(),
- },
- on: {
- click: onClick,
- },
+ prefixCls: `${prefixCls}-menu`,
+ getPopupContainer: () => this.getPopupDomNode(),
+ onClick,
};
- if (typeof overlayElement.type === 'string') {
- delete extraOverlayProps.props.prefixCls;
+ if (overlayElement && overlayElement.type === Text) {
+ delete extraOverlayProps.prefixCls;
}
- return cloneElement($slots.overlay[0], extraOverlayProps);
+ return cloneElement(overlayElement, extraOverlayProps);
},
getMenuElementOrLambda() {
- const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
+ const overlay = this.overlay || this.$slots.overlay;
if (typeof overlay === 'function') {
return this.getMenuElement;
}
@@ -132,7 +130,7 @@ export default {
afterVisibleChange(visible) {
if (visible && this.getMinOverlayWidthMatchTrigger()) {
const overlayNode = this.getPopupDomNode();
- const rootNode = this.$el;
+ const rootNode = findDOMNode(this);
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) {
overlayNode.style.minWidth = `${rootNode.offsetWidth}px`;
if (
@@ -147,10 +145,10 @@ export default {
},
renderChildren() {
- const children = this.$slots.default && this.$slots.default[0];
+ const children = getSlot(this);
const { sVisible } = this;
return sVisible && children
- ? cloneElement(children, { class: this.getOpenClassName() })
+ ? cloneElement(children[0], { class: this.getOpenClassName() }, false)
: children;
},
},
@@ -176,33 +174,25 @@ export default {
}
const triggerProps = {
- props: {
- ...otherProps,
- prefixCls,
- popupClassName: overlayClassName,
- popupStyle: overlayStyle,
- builtinPlacements: placements,
- action: trigger,
- showAction,
- hideAction: triggerHideAction || [],
- popupPlacement: placement,
- popupAlign: align,
- popupTransitionName: transitionName,
- popupAnimation: animation,
- popupVisible: this.sVisible,
- afterPopupVisibleChange: this.afterVisibleChange,
- getPopupContainer,
- },
- on: {
- popupVisibleChange: this.onVisibleChange,
- },
+ ...otherProps,
+ prefixCls,
+ popupClassName: overlayClassName,
+ popupStyle: overlayStyle,
+ builtinPlacements: placements,
+ action: trigger,
+ showAction,
+ hideAction: triggerHideAction || [],
+ popupPlacement: placement,
+ popupAlign: align,
+ popupTransitionName: transitionName,
+ popupAnimation: animation,
+ popupVisible: this.sVisible,
+ afterPopupVisibleChange: this.afterVisibleChange,
+ getPopupContainer,
+ onPopupVisibleChange: this.onVisibleChange,
+ popup: this.getMenuElementOrLambda(),
ref: 'trigger',
};
- return (
-
- {this.renderChildren()}
- {this.$slots.overlay && this.getMenuElement()}
-
- );
+ return {this.renderChildren()};
},
};
diff --git a/components/vc-trigger/LazyRenderBox.jsx b/components/vc-trigger/LazyRenderBox.jsx
index bbc656ca0..83f3b7c3d 100644
--- a/components/vc-trigger/LazyRenderBox.jsx
+++ b/components/vc-trigger/LazyRenderBox.jsx
@@ -1,3 +1,4 @@
+import { Text } from 'vue';
import PropTypes from '../_util/vue-types';
import { getSlot } from '../_util/props-util';
@@ -10,7 +11,11 @@ export default {
render() {
const { hiddenClassName } = this.$props;
const child = getSlot(this);
- if (hiddenClassName || (child && child.length > 1)) {
+ if (
+ hiddenClassName ||
+ (child && child.length > 1) ||
+ (child && child[0] && child[0].type === Text)
+ ) {
// const cls = '';
// if (!visible && hiddenClassName) {
// // cls += ` ${hiddenClassName}`
diff --git a/examples/index.js b/examples/index.js
index dedf6245a..9f0851cfd 100644
--- a/examples/index.js
+++ b/examples/index.js
@@ -32,6 +32,7 @@ import message from 'ant-design-vue/message';
import Modal from 'ant-design-vue/modal';
import Menu from 'ant-design-vue/menu';
import Mentions from 'ant-design-vue/mentions';
+import Dropdown from 'ant-design-vue/dropdown';
import 'ant-design-vue/style.js';
const basic = {
@@ -77,4 +78,5 @@ app
.use(Modal)
.use(Menu)
.use(Mentions)
+ .use(Dropdown)
.mount('#app');