From 9a8eb4d27758c23f83f73d3a6bb74a4b6ba39e6b Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 11 Jan 2018 18:53:51 +0800 Subject: [PATCH] add toolTip --- components/_util/vnode.js | 12 + components/button/button.vue | 1 + components/index.js | 2 +- components/style.js | 1 + .../tooltip/demo/arrow-point-at-center.vue | 24 ++ .../tooltip/demo/auto-adjust-overflow.vue | 43 ++ components/tooltip/demo/basic.vue | 23 ++ components/tooltip/demo/index.vue | 111 +----- components/tooltip/demo/placement.vue | 112 ++++++ components/tooltip/index.js | 1 - components/tooltip/placements.js | 88 +++++ components/tooltip/src/Tooltip.vue | 108 +++++ components/tooltip/src/index.js | 3 + components/tooltip/src/placements.js | 83 ++++ components/tooltip/tooltip.vue | 368 ++++++++---------- components/trigger/Popup.vue | 17 +- components/trigger/index.md | 8 +- components/trigger/index.vue | 24 +- components/trigger/utils.js | 4 +- examples/index.less | 4 +- examples/md.vue | 3 +- 21 files changed, 698 insertions(+), 342 deletions(-) create mode 100644 components/tooltip/demo/arrow-point-at-center.vue create mode 100644 components/tooltip/demo/auto-adjust-overflow.vue create mode 100644 components/tooltip/demo/basic.vue create mode 100644 components/tooltip/demo/placement.vue create mode 100644 components/tooltip/placements.js create mode 100644 components/tooltip/src/Tooltip.vue create mode 100644 components/tooltip/src/index.js create mode 100644 components/tooltip/src/placements.js diff --git a/components/_util/vnode.js b/components/_util/vnode.js index 8068ea46f..ecf245b82 100644 --- a/components/_util/vnode.js +++ b/components/_util/vnode.js @@ -93,3 +93,15 @@ export function cloneElement (n, nodeProps, clone) { export function getComponentName (opts) { return opts && (opts.Ctor.options.name || opts.tag) } + +export function isValidElement (ele) { + return !!ele.tag +} + +export function getClass (ele) { + return ele.data && (ele.data.class || ele.data.staticClass) +} + +export function getStyle (ele) { + return ele.data && (ele.data.style || ele.data.staticStyle) +} diff --git a/components/button/button.vue b/components/button/button.vue index 031d056ec..39b78a8d0 100644 --- a/components/button/button.vue +++ b/components/button/button.vue @@ -4,6 +4,7 @@ const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/ const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar) export default { name: 'Button', + __ANT_BUTTON: true, components: { Icon }, props: { prefixCls: { diff --git a/components/index.js b/components/index.js index d430782f9..a9981c3ec 100644 --- a/components/index.js +++ b/components/index.js @@ -10,7 +10,7 @@ export { default as Grid } from './grid' export { default as Rate } from './rate' -export { default as ToolTip } from './tooltip' +export { default as Tooltip } from './tooltip' export { default as Pagination } from './pagination' diff --git a/components/style.js b/components/style.js index ec801667d..fa65f1323 100644 --- a/components/style.js +++ b/components/style.js @@ -10,5 +10,6 @@ import './avatar/style' import './badge/style' import './tabs/style' import './input/style' +import './tooltip/style' import './menu/style' diff --git a/components/tooltip/demo/arrow-point-at-center.vue b/components/tooltip/demo/arrow-point-at-center.vue new file mode 100644 index 000000000..643386649 --- /dev/null +++ b/components/tooltip/demo/arrow-point-at-center.vue @@ -0,0 +1,24 @@ + + + diff --git a/components/tooltip/demo/auto-adjust-overflow.vue b/components/tooltip/demo/auto-adjust-overflow.vue new file mode 100644 index 000000000..585815999 --- /dev/null +++ b/components/tooltip/demo/auto-adjust-overflow.vue @@ -0,0 +1,43 @@ + + + diff --git a/components/tooltip/demo/basic.vue b/components/tooltip/demo/basic.vue new file mode 100644 index 000000000..b60af9327 --- /dev/null +++ b/components/tooltip/demo/basic.vue @@ -0,0 +1,23 @@ + + + diff --git a/components/tooltip/demo/index.vue b/components/tooltip/demo/index.vue index 178db3bff..b8c54ed5b 100644 --- a/components/tooltip/demo/index.vue +++ b/components/tooltip/demo/index.vue @@ -1,97 +1,26 @@ - - diff --git a/components/tooltip/demo/placement.vue b/components/tooltip/demo/placement.vue new file mode 100644 index 000000000..36aec0438 --- /dev/null +++ b/components/tooltip/demo/placement.vue @@ -0,0 +1,112 @@ + + + + diff --git a/components/tooltip/index.js b/components/tooltip/index.js index b93dd566a..4b5f7d8bc 100644 --- a/components/tooltip/index.js +++ b/components/tooltip/index.js @@ -1,4 +1,3 @@ import ToolTip from './tooltip.vue' -import './style' export default ToolTip diff --git a/components/tooltip/placements.js b/components/tooltip/placements.js new file mode 100644 index 000000000..f3b6bd8e8 --- /dev/null +++ b/components/tooltip/placements.js @@ -0,0 +1,88 @@ +import { placements as rcPlacements } from './src/placements' + +const autoAdjustOverflowEnabled = { + adjustX: 1, + adjustY: 1, +} + +const autoAdjustOverflowDisabled = { + adjustX: 0, + adjustY: 0, +} + +const targetOffset = [0, 0] + +export function getOverflowOptions (autoAdjustOverflow) { + if (typeof autoAdjustOverflow === 'boolean') { + return autoAdjustOverflow ? autoAdjustOverflowEnabled : autoAdjustOverflowDisabled + } + return { + ...autoAdjustOverflowDisabled, + ...autoAdjustOverflow, + } +} + +export default function getPlacements (config) { + const { arrowWidth = 5, horizontalArrowShift = 16, verticalArrowShift = 12, autoAdjustOverflow = true } = config + const placementMap = { + left: { + points: ['cr', 'cl'], + offset: [-4, 0], + }, + right: { + points: ['cl', 'cr'], + offset: [4, 0], + }, + top: { + points: ['bc', 'tc'], + offset: [0, -4], + }, + bottom: { + points: ['tc', 'bc'], + offset: [0, 4], + }, + topLeft: { + points: ['bl', 'tc'], + offset: [-(horizontalArrowShift + arrowWidth), -4], + }, + leftTop: { + points: ['tr', 'cl'], + offset: [-4, -(verticalArrowShift + arrowWidth)], + }, + topRight: { + points: ['br', 'tc'], + offset: [horizontalArrowShift + arrowWidth, -4], + }, + rightTop: { + points: ['tl', 'cr'], + offset: [4, -(verticalArrowShift + arrowWidth)], + }, + bottomRight: { + points: ['tr', 'bc'], + offset: [horizontalArrowShift + arrowWidth, 4], + }, + rightBottom: { + points: ['bl', 'cr'], + offset: [4, verticalArrowShift + arrowWidth], + }, + bottomLeft: { + points: ['tl', 'bc'], + offset: [-(horizontalArrowShift + arrowWidth), 4], + }, + leftBottom: { + points: ['br', 'cl'], + offset: [-4, verticalArrowShift + arrowWidth], + }, + } + Object.keys(placementMap).forEach(key => { + placementMap[key] = config.arrowPointAtCenter ? { + ...placementMap[key], + overflow: getOverflowOptions(autoAdjustOverflow), + targetOffset, + } : { + ...rcPlacements[key], + overflow: getOverflowOptions(autoAdjustOverflow), + } + }) + return placementMap +} diff --git a/components/tooltip/src/Tooltip.vue b/components/tooltip/src/Tooltip.vue new file mode 100644 index 000000000..5d13ae671 --- /dev/null +++ b/components/tooltip/src/Tooltip.vue @@ -0,0 +1,108 @@ + diff --git a/components/tooltip/src/index.js b/components/tooltip/src/index.js new file mode 100644 index 000000000..331785904 --- /dev/null +++ b/components/tooltip/src/index.js @@ -0,0 +1,3 @@ +import Tooltip from './Tooltip' + +export default Tooltip diff --git a/components/tooltip/src/placements.js b/components/tooltip/src/placements.js new file mode 100644 index 000000000..80917822e --- /dev/null +++ b/components/tooltip/src/placements.js @@ -0,0 +1,83 @@ +const autoAdjustOverflow = { + adjustX: 1, + adjustY: 1, +} + +const targetOffset = [0, 0] + +export const placements = { + left: { + points: ['cr', 'cl'], + overflow: autoAdjustOverflow, + offset: [-4, 0], + targetOffset, + }, + right: { + points: ['cl', 'cr'], + overflow: autoAdjustOverflow, + offset: [4, 0], + targetOffset, + }, + top: { + points: ['bc', 'tc'], + overflow: autoAdjustOverflow, + offset: [0, -4], + targetOffset, + }, + bottom: { + points: ['tc', 'bc'], + overflow: autoAdjustOverflow, + offset: [0, 4], + targetOffset, + }, + topLeft: { + points: ['bl', 'tl'], + overflow: autoAdjustOverflow, + offset: [0, -4], + targetOffset, + }, + leftTop: { + points: ['tr', 'tl'], + overflow: autoAdjustOverflow, + offset: [-4, 0], + targetOffset, + }, + topRight: { + points: ['br', 'tr'], + overflow: autoAdjustOverflow, + offset: [0, -4], + targetOffset, + }, + rightTop: { + points: ['tl', 'tr'], + overflow: autoAdjustOverflow, + offset: [4, 0], + targetOffset, + }, + bottomRight: { + points: ['tr', 'br'], + overflow: autoAdjustOverflow, + offset: [0, 4], + targetOffset, + }, + rightBottom: { + points: ['bl', 'br'], + overflow: autoAdjustOverflow, + offset: [4, 0], + targetOffset, + }, + bottomLeft: { + points: ['tl', 'bl'], + overflow: autoAdjustOverflow, + offset: [0, 4], + targetOffset, + }, + leftBottom: { + points: ['br', 'bl'], + overflow: autoAdjustOverflow, + offset: [-4, 0], + targetOffset, + }, +} + +export default placements diff --git a/components/tooltip/tooltip.vue b/components/tooltip/tooltip.vue index 97065950d..6c19912d2 100644 --- a/components/tooltip/tooltip.vue +++ b/components/tooltip/tooltip.vue @@ -1,121 +1,137 @@ diff --git a/components/trigger/Popup.vue b/components/trigger/Popup.vue index 1e68745ad..38a314044 100644 --- a/components/trigger/Popup.vue +++ b/components/trigger/Popup.vue @@ -56,11 +56,9 @@ export default { 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) { + popupDomNode.className = popupDomNode.className.replace(this.currentAlignClassName, currentAlignClassName) this.currentAlignClassName = currentAlignClassName - popupDomNode.className = this.getClassName(currentAlignClassName) } this.$emit('align', popupDomNode, align) }, @@ -101,14 +99,6 @@ export default { onMouseLeave (e) { this.$emit('mouseleave', e) }, - beforeEnter (el) { - try { - // this.$refs.alignInstance && this.$refs.alignInstance.forceAlign() - } catch (error) { - - } - this.$refs.alignInstance && this.$refs.alignInstance.forceAlign() - }, afterLeave (el) { if (this.destroyPopupOnHide) { this.destroyPopup = true @@ -117,8 +107,8 @@ export default { getPopupElement () { const { $props: props, onMouseEnter, onMouseLeave, $slots } = this const { align, visible, prefixCls, animation } = props - const className = this.getClassName(this.currentAlignClassName || - props.getClassNameFromAlign(align)) + this.currentAlignClassName = this.currentAlignClassName || props.getClassNameFromAlign(align) + const className = this.getClassName(this.currentAlignClassName) // const hiddenClassName = `${prefixCls}-hidden` if (!visible) { this.currentAlignClassName = null @@ -144,7 +134,6 @@ export default { } return ( builtin placement align map. used by placement prop - popupVisibleChange - $emit(visible) + onPopupVisibleChange + function call when popup visible is changed - popupAlign - $emit(popupDomNode, align) + onPopupAlign + function callback when popup node is aligned diff --git a/components/trigger/index.vue b/components/trigger/index.vue index 3313d0aba..a56b5310c 100644 --- a/components/trigger/index.vue +++ b/components/trigger/index.vue @@ -5,7 +5,7 @@ import hasProp from '../_util/hasProp' import addEventListener from '../_util/Dom/addEventListener' import warning from '../_util/warning' import Popup from './Popup' -import { getAlignFromPlacement, getPopupClassNameFromAlign } from './utils' +import { getAlignFromPlacement, getPopupClassNameFromAlign, noop } from './utils' import StateMixin from '../_util/StateMixin' import { cloneElement, cloneVNode } from '../_util/vnode' @@ -27,8 +27,8 @@ export default { showAction: PropTypes.any.def([]), hideAction: PropTypes.any.def([]), getPopupClassNameFromAlign: PropTypes.any.def(returnEmptyString), - // onPopupVisibleChange: PropTypes.func, - // afterPopupVisibleChange: PropTypes.func, + // onPopupVisibleChange: PropTypes.func.def(noop), + afterPopupVisibleChange: PropTypes.func.def(noop), popup: PropTypes.any, popupStyle: PropTypes.object.def({}), prefixCls: PropTypes.string.def('rc-trigger-popup'), @@ -51,7 +51,7 @@ export default { destroyPopupOnHide: PropTypes.bool.def(false), mask: PropTypes.bool.def(false), maskClosable: PropTypes.bool.def(true), - // onPopupAlign: PropTypes.func, + // onPopupAlign: PropTypes.func.def(noop), popupAlign: PropTypes.object.def({}), popupVisible: PropTypes.bool, defaultPopupVisible: PropTypes.bool.def(false), @@ -96,7 +96,7 @@ export default { }, sPopupVisible (val) { this.$nextTick(() => { - this.$emit('afterPopupVisibleChange', val) + this.afterPopupVisibleChange(val) }) }, }, @@ -261,7 +261,7 @@ export default { return this.$el.children ? this.$el.children[0] : this.$el }, - getPopupClassFromAlign (align) { + handleGetPopupClassFromAlign (align) { const className = [] const props = this.$props const { popupPlacement, builtinPlacements, prefixCls } = props @@ -285,7 +285,7 @@ export default { onPopupAlign () { this.$emit('popupAlign', ...arguments) }, - getComponent () { + getComponent (h) { const mouseProps = {} if (this.isMouseEnterToShow()) { mouseProps.mouseenter = this.onPopupMouseenter @@ -295,7 +295,7 @@ export default { } const { prefixCls, destroyPopupOnHide, sPopupVisible, popupStyle, popupClassName, action, onPopupAlign, - popupAnimation, getPopupClassFromAlign, getRootDomNode, + popupAnimation, handleGetPopupClassFromAlign, getRootDomNode, mask, zIndex, popupTransitionName, getPopupAlign, maskAnimation, maskTransitionName, popup, $slots, getContainer } = this const popupProps = { @@ -306,7 +306,7 @@ export default { action, align: getPopupAlign(), animation: popupAnimation, - getClassNameFromAlign: getPopupClassFromAlign, + getClassNameFromAlign: handleGetPopupClassFromAlign, getRootDomNode, mask, zIndex, @@ -328,7 +328,7 @@ export default { {...popupProps} ref='popup' > - {typeof popup === 'function' ? popup() : popup} + {typeof popup === 'function' ? popup(h) : popup} {popup === undefined ? $slots.popup : null} ) @@ -472,7 +472,7 @@ export default { this.setPopupVisible(false) }, }, - render () { + render (h) { const children = this.$slots.default if (children.length > 1) { warning(false, 'Trigger $slots.default.length > 1, just support only one default', true) @@ -521,7 +521,7 @@ export default { const trigger = cloneElement(cloneVNode(child), newChildProps) const { sPopupVisible, forceRender } = this if (sPopupVisible || forceRender || this._component) { - this._component = this.getComponent() + this._component = this.getComponent(h) } else { this._component = null } diff --git a/components/trigger/utils.js b/components/trigger/utils.js index e2af70378..eddd8178f 100644 --- a/components/trigger/utils.js +++ b/components/trigger/utils.js @@ -21,7 +21,5 @@ export function getPopupClassNameFromAlign (builtinPlacements, prefixCls, align) } return '' } - -export function saveRef (name, component) { - this[name] = component +export function noop () { } diff --git a/examples/index.less b/examples/index.less index 89a9f27d5..ac6ec4a44 100644 --- a/examples/index.less +++ b/examples/index.less @@ -1,3 +1,3 @@ -.icon-test{ - font-size: 35px; +#app { + padding: 50px; } diff --git a/examples/md.vue b/examples/md.vue index 9dcad410f..c907d5dda 100644 --- a/examples/md.vue +++ b/examples/md.vue @@ -1,5 +1,5 @@