# 手写qtip插件
qtip就是鼠标移入显示一个提示框的功能,名字来源于jq的qtip插件。
由于项目不需要jq,所以这里自己动手实现一个。
# 实现
因为是在G6.js
下开发,所以直接用他们的修改css和创建dom方法了。
主要逻辑就是通过对传入的dom元素进行遍历,找出所有包含qtip
(名字可自定义)的元素,增加鼠标事件。
如果鼠标的x,y加上偏移值没超出边界,就使用该值。
超出了则用鼠标的x,y减去该显示元素的宽高。
/**
* qTip
* 鼠标hover的弹窗提示插件
*/
import modifyCSS from '@antv/dom-util/lib/modify-css';
import createDOM from '@antv/dom-util/lib/create-dom';
import mergeWith from 'lodash/mergeWith';
import { qTipConfig } from '@/config/plugins';
import '@/style/qTip.less';
class QTip {
constructor(config) {
this._config = mergeWith(
{},
qTipConfig,
config
);
this.initBindEvent();
this.initQTip();
}
initBindEvent() {
const _this = this;
this.bindEventMouseEnter = function(e) {
_this.eventMouseEnter(e);
};
this.bindEventMouseLeave = function(e) {
_this.eventMouseLeave(e);
};
this.bindEventMouseMove = function(e) {
_this.eventMouseMove(e);
};
}
initQTip() {
this.initListener();
}
/**
* 对传入dom遍历监听 qTip:xx 属性
*/
initListener() {
const { target, qTipSymbol } = this._config;
if (!target) {
window.graphConsole.info(window._('传入参数错误:'), window._('target不存在'));
return false;
}
const attributeName = `[${qTipSymbol}]`;
this.ListenerChildren = Array.from(target.querySelectorAll(attributeName));
this.ListenerChildren.forEach(child => {
child.addEventListener('mouseenter', this.bindEventMouseEnter);
child.addEventListener('mouseleave', this.bindEventMouseLeave);
child.addEventListener('mousemove', this.bindEventMouseMove);
});
}
eventMouseEnter(e) {
this.showTip(e);
}
eventMouseLeave() {
modifyCSS(this.dom, {
visibility: 'hidden'
});
}
eventMouseMove(e) {
this.showTip(e);
}
showTip(e) {
const { dom, graph, offsetX, offsetY, qTipSymbol, style } = this._config;
const { target, clientX, clientY } = e;
const graphWidth = graph.get('width');
const graphHeight = graph.get('height');
let tip;
let targetEle = target;
while (!tip) {
// 事件是子元素触发时,向上找
tip = targetEle.getAttribute(qTipSymbol);
targetEle = targetEle.parentNode;
}
// 减少dom操作
if (!this.dom) {
this.dom = createDOM(dom);
graph.get('container').appendChild(this.dom);
}
this.dom.innerHTML = tip;
const { width, height } = this.dom.getBoundingClientRect();
let x = clientX + offsetX;
let y = clientY + offsetY;
if (x + width > graphWidth) {
x = x - width - offsetX;
}
if (y + height > graphHeight) {
y = y - height - offsetY;
}
modifyCSS(this.dom, {
left: x + 'px',
top: y + 'px',
visibility: 'visible',
...style
});
}
removeListener() {
this.ListenerChildren.forEach(child => {
child.removeEventListener('mouseenter', this.bindEventMouseEnter);
child.removeEventListener('mouseleave', this.bindEventMouseLeave);
child.removeEventListener('mousemove', this.bindEventMouseMove);
});
}
destroy() {
this.removeListener();
}
}
export default QTip;
← webpack5踩坑记录 web端首页优化 →