import { VNode } from 'vue'; import { IBzTooltipUtil } from './ibz-tooltip-util'; import { off, on } from '@ibizstudio/runtime'; import { DirectiveBinding } from 'vue/types/options'; /** * 全局tip提示控制器 * * @export * @class IBzTooltipController */ export class IBzTooltipController { /** * 提示工具 * * @type {IBzTooltipUtil} * @memberof IBzTooltipController */ private tipUtil: IBzTooltipUtil = new IBzTooltipUtil(this); /** * 是否悬浮于元素上 * * @memberof IBzTooltipController */ isHover: boolean = false; /** * 定制器 * * @type {*} * @memberof IBzTooltipController */ private timer: NodeJS.Timeout | null = null; /** * 绑定 * * @param {HTMLDivElement} el * @param {DirectiveBinding} binding * @param {VNode} vNode * @param {VNode} oldVNode * @memberof IBzTooltipController */ bind(el: HTMLDivElement, binding: DirectiveBinding, vNode: VNode) { el.onmouseenter = () => { if (this.timer) { clearTimeout(this.timer); this.timer = null; } this.isHover = true; const data: any = { placement: 'auto', delay: 300 }; this.calcAttrs(vNode.data?.attrs, data); this.calcParams(el, data); if (!data.content) { data.content = binding.value; } this.timer = setTimeout(() => { this.tipUtil.openPopover(el, data.content, data.placement, data.mode); }, data.delay); }; el.onmouseleave = () => { this.destroy(); }; on(el, 'click', this.click); } /** * 取消绑定 * * @param {HTMLDivElement} el * @param {DirectiveBinding} binding * @param {VNode} vNode * @param {VNode} oldVNode * @memberof IBzTooltipController */ unbind(el: HTMLDivElement, binding: DirectiveBinding, vNode: VNode) { el.onmouseenter = null; el.onmouseleave = null; off(el, 'click', this.click); } /** * 项单机 * * @private * @param {MouseEvent} e * @memberof IBzTooltipController */ private click = (e: MouseEvent) => { this.destroy(); }; /** * 销毁 * * @private * @memberof IBzTooltipController */ private destroy(): void { if (this.timer) { clearTimeout(this.timer); this.timer = null; } this.isHover = false; this.timer = setTimeout(() => { if (!this.tipUtil.isHover) { this.tipUtil.popperDestroy(); } }, 50); } /** * 计算输入属性 * * @private * @param {*} attrs * @param {*} data * @memberof IBzTooltipController */ private calcAttrs(attrs: any, data: any): void { if (!attrs) { return; } // 在异步模式下的参数 if (attrs['ibz-tip-render']) { data.content = attrs['ibz-tip-render']; } } /** * 参数计算 * * @private * @param {HTMLDivElement} el * @param {*} data * @memberof IBzTooltipController */ private calcParams(el: HTMLDivElement, data: any) { const attrs = el.attributes; // tooltip呈现模式,默认为本地模式[local],或者采用异步呈现[async] this.fillAttrItem(attrs, 'mode', data); // 提示框显示的方向 this.fillAttrItem(attrs, 'placement', data); // 缓冲等待时间,单位:毫秒,默认300毫秒 this.fillAttrItem(attrs, 'delay', data); // 计算参数 const paramsStr = attrs.getNamedItem('ibz-tip-params'); if (paramsStr) { try { data.params = JSON.parse(paramsStr.value); } catch (err) { console.log('动态tip提示参数解析错误', err); } } // 当提供render时,采用render绘制提示 if (data.content) { return; } if (data.mode === 'async') { // 绘制异步tip data.content = (h: any) => { return ; }; } else if (attrs.getNamedItem('ibz-tip-content')) { this.fillAttrItem(attrs, 'content', data); } } /** * 填充参数项 * * @private * @param {NamedNodeMap} attrs * @param {string} name * @param {*} data * @memberof IBzTooltipController */ private fillAttrItem(attrs: NamedNodeMap, name: string, data: any): void { const item = attrs.getNamedItem('ibz-tip-' + name); if (item) { data[name] = item.value; } } /** * 重新计算tip位置 * * @memberof IBzTooltipController */ tick(): void { this.tipUtil.popperTick(); } } /** * tooltip控制器实例 */ export const itc = new IBzTooltipController(); // 挂载在window上 window.itc = itc;