vue3 自定义tootip组件


<template>
  <div>
    <div ref="triggerSlot">
      <slot name="trigger"></slot>
    </div>
    <div class="tooltip" :style="{ top: `${top}px`, left: `${left}px`, opacity: `${opacity}` }">
      <span ref="tipOpacity"><slot></slot></span>
      <span class="sanjiao"></span>
    </div>
  </div>
</template>  
  
<script>
import { ref, onMounted, onUnmounted, nextTick } from 'vue';

export default {
  name: 'Tooltip',

  setup(props, { emit }) {
    const top = ref(0);
    const left = ref(0);
    const triggerSlot = ref(null);
    let tipOpacity = ref(null);
    let opacity = ref(0);

    const handleMouseEnter = () => {
      const triggerEl = triggerSlot.value;
      console.log('triggerEl', triggerEl.getBoundingClientRect());
      if (triggerEl) {
        let gsrg = tipOpacity.value.getBoundingClientRect();
        const rect = triggerEl.getBoundingClientRect();
        top.value = rect.top - rect.height - 30;
        left.value = rect.left + (rect.width / 2 - gsrg.width / 2);
      }
      opacity.value = 1;
    };

    const handleMouseLeave = () => {
      console.log('handleMouseLeave');
      opacity.value = 0;
    };

    onMounted(async () => {
      await nextTick(); // 确保DOM已经更新
      const triggerEl = triggerSlot.value;
      if (triggerEl) {
        triggerEl.addEventListener('mouseover', handleMouseEnter);
        triggerEl.addEventListener('mouseout', handleMouseLeave);
      }
    });

    onUnmounted(() => {
      const triggerEl = triggerSlot.value;
      if (triggerEl) {
        triggerEl.removeEventListener('mouseover', handleMouseEnter);
        triggerEl.removeEventListener('mouseout', handleMouseLeave);
      }
    });

    return {
      opacity,
      tipOpacity,
      top,
      left,
      triggerSlot,
    };
  },
};
</script>  
  
<style scoped>
.tooltip {
  position: fixed;
  z-index: 9;
  max-width: 300px;
  padding: 10px;
  border-radius: 4px;
  box-sizing: border-box;
  font-size: 13px;
  line-height: 1.5;
  background: #ffffff;
  border: 1px solid #e4e7ed;
}
.sanjiao {
  width: 10px;
  height: 10px;
  position: absolute;
  bottom: -5px;
  left: 50%;
}
.sanjiao::before {
  border-top-color: transparent !important;
  border-left-color: transparent !important;
  border-bottom-right-radius: 2px;
  border: 1px solid #e4e7ed;
  background: #ffffff;
  right: 0;
  position: absolute;
  width: 10px;
  height: 10px;
  z-index: -1;
  content: ' ';
  transform: rotate(45deg);
  box-sizing: border-box;
}
</style>
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值