diff --git a/examples/popup/popup.md b/examples/popup/popup.md index 648fa41d1..34119a83e 100644 --- a/examples/popup/popup.md +++ b/examples/popup/popup.md @@ -13,7 +13,7 @@ disabled | Boolean | false | 是否禁用组件 | N hideEmptyPopup | Boolean | false | 【开发中】浮层是否隐藏空内容,默认不隐藏 | N overlayClassName | String / Object / Array | - | 浮层类名,示例:'name1 name2 name3' 或 `['name1', 'name2']` 或 `[{ 'name1': true }]`。TS 类型:`ClassName`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N overlayStyle | Boolean / Object / Function | - | 浮层样式,第一个参数 `triggerElement` 表示触发元素 DOM 节点,第二个参数 `popupElement` 表示浮层元素 DOM 节点。TS 类型:`Styles | ((triggerElement: HTMLElement, popupElement: HTMLElement) => Styles)`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N -placement | String | top | 浮层出现位置。可选项:top/left/right/bottom/top-left/top-right/bottom-left/bottom-right/left-top/left-bottom/right-top/right-bottom | N +placement | String | top | 浮层出现位置。TS 类型:`PopupPlacement` `type PopupPlacement = 'top'|'left'|'right'|'bottom'|'top-left'|'top-right'|'bottom-left'|'bottom-right'|'left-top'|'left-bottom'|'right-top'|'right-bottom'`。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/popup/type.ts) | N showArrow | Boolean | false | 是否显示浮层箭头 | N trigger | String | hover | 触发浮层出现的方式。可选项:hover/click/focus/context-menu | N triggerElement | String / Slot / Function | - | 触发元素。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N @@ -21,11 +21,11 @@ visible | Boolean | false | 是否显示浮层。支持语法糖 `v-model`。TS defaultVisible | Boolean | false | 是否显示浮层。非受控属性。TS 类型:`boolean` | N zIndex | Number | - | 组件层级,Web 侧样式默认为 5500,移动端和小程序样式默认为 1500 | N onScroll | Function | | TS 类型:`(context: { e: WheelEvent }) => void`
下拉选项滚动事件 | N -onVisibleChange | Function | | TS 类型:`(visible: boolean, context: PopupVisibleChangeContext) => void`
当浮层隐藏或显示时触发。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/popup/type.ts)。
`interface PopupVisibleChangeContext { e?: PopupTriggerEvent; trigger?: PopupTriggerSource }`

`type PopupTriggerEvent = MouseEvent | FocusEvent | KeyboardEvent`

`type PopupTriggerSource = 'document' | 'trigger-element-click' | 'trigger-element-hover' | 'trigger-element-blur' | 'trigger-element-focus' | 'context-menu' | 'keydown-esc'`
| N +onVisibleChange | Function | | TS 类型:`(visible: boolean, context: PopupVisibleChangeContext) => void`
当浮层隐藏或显示时触发,`trigger=document` 表示点击非浮层元素触发;`trigger=document` 表示右击触发。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/popup/type.ts)。
`interface PopupVisibleChangeContext { e?: PopupTriggerEvent; trigger?: PopupTriggerSource }`

`type PopupTriggerEvent = MouseEvent | FocusEvent | KeyboardEvent`

`type PopupTriggerSource = 'document' | 'trigger-element-click' | 'trigger-element-hover' | 'trigger-element-blur' | 'trigger-element-focus' | 'context-menu' | 'keydown-esc'`
| N ### Popup Events 名称 | 参数 | 描述 -- | -- | -- scroll | `(context: { e: WheelEvent })` | 下拉选项滚动事件 -visible-change | `(visible: boolean, context: PopupVisibleChangeContext)` | 当浮层隐藏或显示时触发。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/popup/type.ts)。
`interface PopupVisibleChangeContext { e?: PopupTriggerEvent; trigger?: PopupTriggerSource }`

`type PopupTriggerEvent = MouseEvent | FocusEvent | KeyboardEvent`

`type PopupTriggerSource = 'document' | 'trigger-element-click' | 'trigger-element-hover' | 'trigger-element-blur' | 'trigger-element-focus' | 'context-menu' | 'keydown-esc'`
+visible-change | `(visible: boolean, context: PopupVisibleChangeContext)` | 当浮层隐藏或显示时触发,`trigger=document` 表示点击非浮层元素触发;`trigger=document` 表示右击触发。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/popup/type.ts)。
`interface PopupVisibleChangeContext { e?: PopupTriggerEvent; trigger?: PopupTriggerSource }`

`type PopupTriggerEvent = MouseEvent | FocusEvent | KeyboardEvent`

`type PopupTriggerSource = 'document' | 'trigger-element-click' | 'trigger-element-hover' | 'trigger-element-blur' | 'trigger-element-focus' | 'context-menu' | 'keydown-esc'`
diff --git a/examples/tooltip/demos/mouse.vue b/examples/tooltip/demos/mouse.vue new file mode 100644 index 000000000..ba855fbff --- /dev/null +++ b/examples/tooltip/demos/mouse.vue @@ -0,0 +1,7 @@ + diff --git a/examples/tooltip/tooltip.md b/examples/tooltip/tooltip.md index b19c4b280..957c1c5eb 100644 --- a/examples/tooltip/tooltip.md +++ b/examples/tooltip/tooltip.md @@ -1,5 +1,9 @@ :: BASE_DOC :: +### 模拟原生title + +::: demo demos/mouse +::: ### 定时消失 ::: demo demos/duration @@ -13,6 +17,7 @@ delay | Number | - | 【议案讨论中】延迟出现提示,用于异步加载提示信息需要延迟显示的业务场景下 | N destroyOnClose | Boolean | true | 是否在关闭浮层时销毁浮层 | N duration | Number | - | 用于设置提示默认显示多长时间之后消失,初始第一次有效,单位:毫秒 | N +placement | String | top | 浮层出现位置。TS 类型:`'mouse' | PopupPlacement`,[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue/tree/develop/src/tooltip/type.ts) | N showArrow | Boolean | true | 是否显示浮层箭头 | N theme | String | default | 文字提示风格。可选项:default/primary/success/danger/warning/light | N -PopupProps | - | - | 继承 `PopupProps` 中的全部 API | N +`Omit` | \- | - | 继承 `Omit` 中的全部 API | N diff --git a/examples/tooltip/usage/props.json b/examples/tooltip/usage/props.json index 026b02a63..530f533f1 100644 --- a/examples/tooltip/usage/props.json +++ b/examples/tooltip/usage/props.json @@ -41,5 +41,64 @@ "value": "light" } ] + }, + { + "name": "placement", + "type": "enum", + "defaultValue": "top", + "options": [ + { + "label": "mouse", + "value": "mouse" + }, + { + "label": "top", + "value": "top" + }, + { + "label": "left", + "value": "left" + }, + { + "label": "right", + "value": "right" + }, + { + "label": "bottom", + "value": "bottom" + }, + { + "label": "top-left", + "value": "top-left" + }, + { + "label": "top-right", + "value": "top-right" + }, + { + "label": "bottom-left", + "value": "bottom-left" + }, + { + "label": "bottom-right", + "value": "bottom-right" + }, + { + "label": "left-top", + "value": "left-top" + }, + { + "label": "left-bottom", + "value": "left-bottom" + }, + { + "label": "right-top", + "value": "right-top" + }, + { + "label": "right-bottom", + "value": "right-bottom" + } + ] } ] \ No newline at end of file diff --git a/src/popup/props.ts b/src/popup/props.ts index 9b858e5ee..e1c2569d2 100644 --- a/src/popup/props.ts +++ b/src/popup/props.ts @@ -39,22 +39,6 @@ export default { placement: { type: String as PropType, default: 'top' as TdPopupProps['placement'], - validator(val: TdPopupProps['placement']): boolean { - return [ - 'top', - 'left', - 'right', - 'bottom', - 'top-left', - 'top-right', - 'bottom-left', - 'bottom-right', - 'left-top', - 'left-bottom', - 'right-top', - 'right-bottom', - ].includes(val); - }, }, /** 是否显示浮层箭头 */ showArrow: Boolean, @@ -63,6 +47,7 @@ export default { type: String as PropType, default: 'hover' as TdPopupProps['trigger'], validator(val: TdPopupProps['trigger']): boolean { + if (!val) return true; return ['hover', 'click', 'focus', 'context-menu'].includes(val); }, }, @@ -73,16 +58,13 @@ export default { /** 是否显示浮层 */ visible: Boolean, /** 是否显示浮层,非受控属性 */ - defaultVisible: { - type: Boolean, - default: undefined, - }, + defaultVisible: Boolean, /** 组件层级,Web 侧样式默认为 5500,移动端和小程序样式默认为 1500 */ zIndex: { type: Number, }, /** 下拉选项滚动事件 */ onScroll: Function as PropType, - /** 当浮层隐藏或显示时触发 */ + /** 当浮层隐藏或显示时触发,`trigger=document` 表示点击非浮层元素触发;`trigger=document` 表示右击触发 */ onVisibleChange: Function as PropType, }; diff --git a/src/popup/type.ts b/src/popup/type.ts index c65070cd6..dfe2941fd 100644 --- a/src/popup/type.ts +++ b/src/popup/type.ts @@ -47,19 +47,7 @@ export interface TdPopupProps { * 浮层出现位置 * @default top */ - placement?: - | 'top' - | 'left' - | 'right' - | 'bottom' - | 'top-left' - | 'top-right' - | 'bottom-left' - | 'bottom-right' - | 'left-top' - | 'left-bottom' - | 'right-top' - | 'right-bottom'; + placement?: PopupPlacement; /** * 是否显示浮层箭头 * @default false @@ -93,11 +81,25 @@ export interface TdPopupProps { */ onScroll?: (context: { e: WheelEvent }) => void; /** - * 当浮层隐藏或显示时触发 + * 当浮层隐藏或显示时触发,`trigger=document` 表示点击非浮层元素触发;`trigger=document` 表示右击触发 */ onVisibleChange?: (visible: boolean, context: PopupVisibleChangeContext) => void; } +export type PopupPlacement = + | 'top' + | 'left' + | 'right' + | 'bottom' + | 'top-left' + | 'top-right' + | 'bottom-left' + | 'bottom-right' + | 'left-top' + | 'left-bottom' + | 'right-top' + | 'right-bottom'; + export interface PopupVisibleChangeContext { e?: PopupTriggerEvent; trigger?: PopupTriggerSource; diff --git a/src/tooltip/props.ts b/src/tooltip/props.ts index b11c07c1b..17b3fa2bb 100644 --- a/src/tooltip/props.ts +++ b/src/tooltip/props.ts @@ -2,22 +2,29 @@ /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC - * updated at 2021-11-19 10:44:26 * */ import { TdTooltipProps } from './type'; import { PropType } from 'vue'; export default { + /** 【议案讨论中】延迟出现提示,用于异步加载提示信息需要延迟显示的业务场景下 */ + delay: { + type: Number, + }, /** 是否在关闭浮层时销毁浮层 */ destroyOnClose: { type: Boolean, default: true, }, - /** 用于设置显示几秒之后消失,初始第一次有效 */ + /** 用于设置提示默认显示多长时间之后消失,初始第一次有效,单位:毫秒 */ duration: { type: Number, - default: 3000, + }, + /** 浮层出现位置 */ + placement: { + type: String as PropType, + default: 'top' as TdTooltipProps['placement'], }, /** 是否显示浮层箭头 */ showArrow: { @@ -29,6 +36,7 @@ export default { type: String as PropType, default: 'default' as TdTooltipProps['theme'], validator(val: TdTooltipProps['theme']): boolean { + if (!val) return true; return ['default', 'primary', 'success', 'danger', 'warning', 'light'].includes(val); }, }, diff --git a/src/tooltip/tooltip.tsx b/src/tooltip/tooltip.tsx index 86db57176..549ac6e97 100644 --- a/src/tooltip/tooltip.tsx +++ b/src/tooltip/tooltip.tsx @@ -1,4 +1,5 @@ import Vue from 'vue'; +import isFunction from 'lodash/isFunction'; import { prefix } from '../config'; import props from './props'; import popupProps from '../popup/props'; @@ -19,6 +20,8 @@ export default Vue.extend({ data() { return { timer: null, + x: 0, + offsetX: 0, tooltipVisible: false, }; }, @@ -26,6 +29,21 @@ export default Vue.extend({ tooltipOverlayClassName(): ClassName { return [`${prefix}-tooltip`, { [`${prefix}-tooltip--${this.theme}`]: this.theme }, this.overlayClassName]; }, + tooltipOverlayStyle(): PopupProps['overlayStyle'] { + if (this.placement !== 'mouse' || this.offsetX === 0) { + return this.overlayStyle; + } + const offsetStyle = (triggerEl: HTMLElement) => ({ + transform: `translateX(${this.offsetX - triggerEl.getBoundingClientRect().left}px)`, + }); + if (this.overlayStyle) { + return (triggerEl: HTMLElement, popupEl: HTMLElement) => ({ + ...offsetStyle(triggerEl), + ...(isFunction(this.overlayStyle) ? this.overlayStyle(triggerEl, popupEl) : this.overlayStyle), + }); + } + return offsetStyle; + }, }, watch: { visible(visible) { @@ -45,20 +63,33 @@ export default Vue.extend({ }, this.duration); } }, + mounted() { + window?.addEventListener('mousemove', this.onMouseMove, { passive: true }); + }, + destroyed() { + window?.removeEventListener('mousemove', this.onMouseMove); + }, methods: { + onMouseMove(e: MouseEvent) { + this.x = e.clientX; + }, + onTipVisibleChange(val: boolean, ctx?: PopupVisibleChangeContext) { // 因 props={this.getPopupProps()} 已经透传 onVisibleChange props,此处不再需要使用 emitEvent if (this.timer && ctx?.trigger !== 'document') return; + if (val) this.offsetX = this.x; this.$emit('visible-change', val); }, getPopupProps(): PopupProps { const r: PopupProps = { - showArrow: true, ...this.$props, + showArrow: this.placement === 'mouse' ? false : this.showArrow, + placement: this.placement === 'mouse' ? 'bottom-left' : this.placement, content: () => renderTNodeJSX(this, 'content'), default: () => renderContent(this, 'default', 'triggerElement'), overlayClassName: this.tooltipOverlayClassName, + overlayStyle: this.tooltipOverlayStyle, }; // delete r.visible; return r; diff --git a/src/tooltip/type.ts b/src/tooltip/type.ts index a265b71f1..bf61ccb76 100644 --- a/src/tooltip/type.ts +++ b/src/tooltip/type.ts @@ -2,22 +2,30 @@ /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC - * updated at 2021-11-19 10:44:26 * */ +import { PopupPlacement } from '../popup'; import { PopupProps } from '../popup'; -export interface TdTooltipProps extends PopupProps { +export interface TdTooltipProps extends Omit { + /** + * 【议案讨论中】延迟出现提示,用于异步加载提示信息需要延迟显示的业务场景下 + */ + delay?: number; /** * 是否在关闭浮层时销毁浮层 * @default true */ destroyOnClose?: boolean; /** - * 用于设置显示几秒之后消失,初始第一次有效 - * @default 3000 + * 用于设置提示默认显示多长时间之后消失,初始第一次有效,单位:毫秒 */ duration?: number; + /** + * 浮层出现位置 + * @default top + */ + placement?: 'mouse' | PopupPlacement; /** * 是否显示浮层箭头 * @default true @@ -28,4 +36,4 @@ export interface TdTooltipProps extends PopupProps { * @default default */ theme?: 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'light'; -}; +} diff --git a/test/ssr/__snapshots__/ssr.test.js.snap b/test/ssr/__snapshots__/ssr.test.js.snap index ab7454451..ccbc1f534 100644 --- a/test/ssr/__snapshots__/ssr.test.js.snap +++ b/test/ssr/__snapshots__/ssr.test.js.snap @@ -16552,6 +16552,8 @@ exports[`ssr snapshot test renders ./examples/tooltip/demos/duration.vue correct `; +exports[`ssr snapshot test renders ./examples/tooltip/demos/mouse.vue correctly 1`] = ``; + exports[`ssr snapshot test renders ./examples/tooltip/demos/no-arrow.vue correctly 1`] = `
`; exports[`ssr snapshot test renders ./examples/tooltip/demos/theme.vue correctly 1`] = `
`;