vTooltipInEditor.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import Vue from 'vue'
  2. import {computePosition, offset, flip, shift, arrow} from '@floating-ui/dom';
  3. let tooltipNode = null
  4. let intervalId = null
  5. function removeTooltip() {
  6. try {
  7. clearInterval(intervalId)
  8. document.body.removeChild(tooltipNode)
  9. } catch(e) {
  10. console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
  11. }
  12. }
  13. Vue.directive('tooltip', {
  14. bind: function (el, binding) {
  15. if (!binding.value) {
  16. return
  17. }
  18. el.addEventListener('mouseenter', function(e) {
  19. tooltipNode = document.createElement('div')
  20. tooltipNode.style.position = 'fixed'
  21. tooltipNode.style.zIndex = 100
  22. tooltipNode.style.backgroundColor = '#191A1C'
  23. tooltipNode.style.border = '1px solid rgba(151, 151, 151, 0.2)'
  24. tooltipNode.style.borderRadius = '3px'
  25. tooltipNode.style.border = '1px solid rgba(151, 151, 151, 0.2)'
  26. tooltipNode.style.boxShadow = '0px 2px 12px 0px rgba(0, 0, 0, 0.06)'
  27. tooltipNode.style.padding = '8px 8px'
  28. tooltipNode.style.fontSize = '12px'
  29. tooltipNode.style.cursor = 'default'
  30. tooltipNode.style.pointerEvents = 'none'
  31. tooltipNode.style.wordBreak = 'keep-all'
  32. tooltipNode.style.whiteSpace = 'pre'
  33. tooltipNode.style.fontSize = '12px'
  34. tooltipNode.style.lineHeight = '17px'
  35. tooltipNode.style.color = 'rgba(255, 255, 255, 0.6)'
  36. tooltipNode.innerText = binding.value
  37. const arrowNode = document.createElement('div')
  38. arrowNode.style.position = 'absolute'
  39. arrowNode.style.backgroundColor = 'inherit'
  40. arrowNode.style.boxSizing = 'border-box'
  41. arrowNode.style.width = '12px'
  42. arrowNode.style.height = '12px'
  43. arrowNode.style.border = '1px solid transparent'
  44. arrowNode.style.borderRight = 'inherit'
  45. arrowNode.style.borderBottom = 'inherit'
  46. arrowNode.style.transform = 'rotate(45deg)'
  47. tooltipNode.appendChild(arrowNode)
  48. document.body.appendChild(tooltipNode)
  49. computePosition(el, tooltipNode, {
  50. placement: 'top',
  51. middleware: [
  52. offset(13),
  53. flip(),
  54. shift({padding: 12}),
  55. arrow({
  56. element: arrowNode,
  57. padding: 3,
  58. }),
  59. ],
  60. }).then(({x, y, placement, middlewareData}) => {
  61. Object.assign(tooltipNode.style, {
  62. left: `${x}px`,
  63. top: `${y}px`,
  64. });
  65. const {x: arrowX, y: arrowY} = middlewareData.arrow;
  66. const staticSide = {
  67. top: 'bottom',
  68. right: 'left',
  69. bottom: 'top',
  70. left: 'right',
  71. }[placement.split('-')[0]];
  72. Object.assign(arrowNode.style, {
  73. left: arrowX != null ? `${arrowX}px` : '',
  74. [staticSide]: '-6px',
  75. });
  76. }).catch((err) => {
  77. console.log('计算tooltip位置时出现异常,可能因为目标元素已经被卸载。')
  78. });
  79. intervalId = setInterval(() => {
  80. if (!document.contains(el)) {
  81. removeTooltip()
  82. }
  83. }, 300);
  84. }, {
  85. passive: false,
  86. })
  87. el.addEventListener('mouseleave', removeTooltip)
  88. el.addEventListener('mousedown', removeTooltip)
  89. el.addEventListener('keydown', removeTooltip)
  90. el.addEventListener('scroll', removeTooltip)
  91. el.addEventListener('dragstart', removeTooltip)
  92. el.addEventListener('dragstart', removeTooltip)
  93. el.addEventListener('dragleave', removeTooltip)
  94. },
  95. })