From c277fe8dba3755214387aebf291da72c94da706c Mon Sep 17 00:00:00 2001 From: Chris lu Date: Wed, 28 Nov 2018 17:04:02 +0800 Subject: [PATCH] =?UTF-8?q?tooltip=E4=BD=BF=E7=94=A8popper=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D=20(#369)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * U tooltip使用popper定位 * U 优化箭头朝向 * U tooltip改造 --- .../src/components/Tooltip/Tooltip.js | 120 ++++++++---------- .../src/styles/modules/_tooltip.scss | 44 ++++--- .../src/styles/variables/_tooltip.scss | 2 +- 3 files changed, 77 insertions(+), 89 deletions(-) diff --git a/packages/react-impression/src/components/Tooltip/Tooltip.js b/packages/react-impression/src/components/Tooltip/Tooltip.js index f08dcbea7..ea00d747f 100644 --- a/packages/react-impression/src/components/Tooltip/Tooltip.js +++ b/packages/react-impression/src/components/Tooltip/Tooltip.js @@ -1,5 +1,8 @@ import React from 'react' +import { Portal } from 'react-portal' import PropTypes from 'prop-types' +import classnames from 'classnames' +import Popper from 'popper.js' export default class Tooltip extends React.PureComponent { static propTypes = { @@ -23,90 +26,71 @@ export default class Tooltip extends React.PureComponent { position: 'right', } - createTooltip(targetRect) { - const { position, content } = this.props - const positionClass = `tooltip-${position}` - const tooltipNode = document.createElement('div') - const arrowNode = document.createElement('div') - const innerNode = document.createElement('div') - - tooltipNode.className = `tooltip ${positionClass}` - arrowNode.className = 'tooltip-arrow' - innerNode.className = 'tooltip-inner' - - innerNode.innerHTML = content - tooltipNode.appendChild(arrowNode) - tooltipNode.appendChild(innerNode) - - document.body.appendChild(tooltipNode) - - const tooltipRect = tooltipNode.getBoundingClientRect() - - /** - * switch - 计算left、top - * - * @param {type} position 位置 - */ - switch (position) { - case 'top': - tooltipNode.style.top = `${targetRect.top - tooltipRect.height - 10}px` - tooltipNode.style.left = `${targetRect.left - - (tooltipRect.width - targetRect.width) / 2}px` - break - case 'left': - tooltipNode.style.left = `${targetRect.left - tooltipRect.width - 10}px` - tooltipNode.style.top = `${targetRect.top + - (targetRect.height - tooltipRect.height) / 2}px` - break - case 'right': - tooltipNode.style.left = `${targetRect.left + targetRect.width + 10}px` - tooltipNode.style.top = `${targetRect.top + - (targetRect.height - tooltipRect.height) / 2}px` - break - default: - tooltipNode.style.top = `${targetRect.top + targetRect.height + 10}px` - tooltipNode.style.left = `${targetRect.left - - (tooltipRect.width - targetRect.width) / 2}px` - break - } - - tooltipNode.classList.add('in') - this.tooltip = tooltipNode + state = { + showTip: false, } /** * 显示tooltip */ onMouseOver = event => { - const rect = event.target.getBoundingClientRect() - - this.createTooltip(rect) + const { position } = this.props + if (!this.popper) { + this.popper = new Popper(event.target, this.tooltip, { + positionFixed: true, + placement: position, + modifiers: { + offset: { offset: '0, 10' }, + }, + }) + } + this.setState({ showTip: true }) } /** * 移除tooltip */ onMouseOut = () => { - document.body.removeChild(this.tooltip) + this.setState({ showTip: false }) } + componentWillUnmount() { + this.popper && this.popper.destroy() + this.popper = null + } + + setTooltipRef = element => (this.tooltip = element) + render() { - const { children } = this.props + const { position, content, children } = this.props const { onMouseOver, onMouseOut } = children.props - return React.cloneElement(children, { - onMouseOver: onMouseOver - ? event => { - onMouseOver() - this.onMouseOver(event) - } - : this.onMouseOver, - onMouseOut: onMouseOut - ? event => { - onMouseOut() - this.onMouseOut(event) - } - : this.onMouseOut, - }) + return ( +
+ {React.cloneElement(children, { + onMouseOver: event => { + onMouseOver && onMouseOver() + this.onMouseOver(event) + }, + onMouseOut: event => { + onMouseOut && onMouseOut() + this.onMouseOut(event) + }, + })} + +
+
+
+
{content}
+
+
+ +
+ ) } } diff --git a/packages/react-impression/src/styles/modules/_tooltip.scss b/packages/react-impression/src/styles/modules/_tooltip.scss index e322223c9..c93ab78b9 100755 --- a/packages/react-impression/src/styles/modules/_tooltip.scss +++ b/packages/react-impression/src/styles/modules/_tooltip.scss @@ -1,21 +1,8 @@ // Base class .tooltip { - position: fixed; z-index: $zindex-tooltip; - display: block; - // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. - // So reset our font and text properties to avoid inheriting weird values. - font-size: $font-size-base; - // Allow breaking very long words so they don't overflow the tooltip's bounds - word-wrap: break-word; - opacity: 0; - transition: $tooltip-transition; - &.in { - opacity: $tooltip-opacity; - } - - &.tooltip-top { + &[x-placement^="top"] { padding-bottom: $tooltip-arrow-width; .tooltip-arrow { @@ -27,7 +14,7 @@ } } - &.tooltip-right { + &[x-placement^="right"] { padding-left: $tooltip-arrow-width; .tooltip-arrow { @@ -35,12 +22,12 @@ left: 0; margin-top: -$tooltip-arrow-width; border-width: $tooltip-arrow-width $tooltip-arrow-width - $tooltip-arrow-width 0; + $tooltip-arrow-width 0; border-right-color: $tooltip-arrow-color; } } - &.tooltip-bottom { + &[x-placement^="bottom"] { padding-top: $tooltip-arrow-width; .tooltip-arrow { @@ -52,7 +39,7 @@ } } - &.tooltip-left { + &[x-placement^="left"] { padding-right: $tooltip-arrow-width; .tooltip-arrow { @@ -60,14 +47,22 @@ right: 0; margin-top: -$tooltip-arrow-width; border-width: $tooltip-arrow-width 0 $tooltip-arrow-width - $tooltip-arrow-width; + $tooltip-arrow-width; border-left-color: $tooltip-arrow-color; } } } +.tooltip-inner { + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + font-size: $font-size-base; + // Allow breaking very long words so they don't overflow the tooltip's bounds + word-wrap: break-word; + animation: $tooltip-animation; +} // Wrapper for the tooltip content -.tooltip-inner { +.tooltip-text { max-width: $tooltip-max-width; padding: $tooltip-padding-y $tooltip-padding-x; color: $tooltip-color; @@ -85,3 +80,12 @@ border-color: transparent; border-style: solid; } +@keyframes tooltipFadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: $tooltip-opacity; + } +} diff --git a/packages/react-impression/src/styles/variables/_tooltip.scss b/packages/react-impression/src/styles/variables/_tooltip.scss index 5dde0f56e..dbccc3e41 100644 --- a/packages/react-impression/src/styles/variables/_tooltip.scss +++ b/packages/react-impression/src/styles/variables/_tooltip.scss @@ -13,4 +13,4 @@ $tooltip-offset: rem(10px) !default; $tooltip-arrow-width: rem(5px) !default; $tooltip-arrow-color: $tooltip-bg !default; -$tooltip-transition: all 0.36s cubic-bezier(0.4, 0, 0.2, 1) !default; +$tooltip-animation: 0.36s tooltipFadeIn cubic-bezier(0.4, 0, 0.2, 1) forwards !default;