<template> <div ref="popTitle" :class="[popContainerClass, 'dsd-title-popover']" :style="popContainerStyle"> <a-popover v-if="visible" ref="popover" v-bind="popoverConfig" :title="title" v-model="popVisible" :overlayStyle="overlayStyle"> <template #content> <div class="popoverContent"> {{ content }} </div> </template> <div ref="popTextContainer" :style="popTextStyle" class="dsd-pop-text cursor-pop"> <slot></slot> </div> </a-popover> <div v-else ref="popTextContainer" :style="popTextStyle" class="dsd-pop-text"> <slot></slot> </div> </div> </template> <script setup lang="ts"> import { ref, reactive, onMounted, onUpdated, onBeforeUnmount, computed } from 'vue'; const popVisible = ref(false) const resizeObs = ref() const visible = ref(true) const popTitle = ref() const popTextContainer = ref() const overlayStyle = reactive({ width: 'auto' }) const props = defineProps({ // 最外围box class popContainerClass: { type: [String, Array], default: null }, // 最外围box style popContainerStyle: { type: Object, default: () => { } }, // popover配置 popConfig: { type: Object, default: () => { } }, // 标题 title: { type: String, default: '' }, // 内容 content: { type: String, default: '' }, // 根据父节点定位 positionByParent: { type: Boolean, default: false }, // 主题 theme: { type: String, default: 'lightTooltip' // darkTooltip | lightTooltip }, // 定为节点 positionNode: { type: Function, default: () => { } }, // 悬浮框宽度,不指定默认与父节点同宽 overlayWidth: { type: String, default: '' }, // 文字插槽样式 popTextStyle: { type: Object, default: () => { } } }) onMounted(() => { const resizeObserver = new ResizeObserver(() => { sizeUpdate() }) resizeObserver.observe(popTitle.value) resizeObs.value = resizeObserver }) onUpdated(() => { sizeUpdate() }) const popoverConfig = computed(() => { let config = props.popConfig config.overlayClassName = config.overlayClassName + ' ' + (props.theme === 'darkTooltip' ? props.theme : 'lightTooltip') return { ...config, getPopupContainer: (el) => getPopupContainer(el) } }) const sizeUpdate = () => { visible.value = popTextContainer.value.offsetWidth < popTextContainer.value.scrollWidth // 悬浮宽度不超过节点 if (!props.overlayWidth.length) { overlayStyle.width = popTextContainer.value.offsetWidth + 'px' } else if (props.overlayWidth === 'auto') { overlayStyle.width = 'auto' } else { overlayStyle.width = props.overlayWidth } } const getPopupContainer = (el) => { let positionNode = null if (!!props.positionNode(popTitle.value)) { positionNode = props.positionNode(popTitle.value) } else { positionNode = props.positionByParent ? el.parentNode : document.querySelector('#dsdApp') } return positionNode } onBeforeUnmount(() => { resizeObs.value.unobserve(popTitle.value) }) </script> <style lang="less" scoped> .dsd-pop-text { // 防止文字溢出显示省略号与原本宽度一直导致tooltip不显示 // width: 100.4%; // width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 17px; } .cursor-pop { cursor: pointer; } .popoverContent { word-break: break-all; } :deep(.dsd-popover) { .dsd-popover-inner-content, .dsd-popover-inner { border-radius: 2px; } } </style> <style lang="less"> .darkTooltip { .dsd-popover-content { .dsd-popover-arrow-content { background: rgba(0, 0, 0, 0.7); } .dsd-popover-inner-content { background: rgba(0, 0, 0, 0.7); color: #fff; } } } </style> Handlebars