fix: 调整名字的宽度

master
xjs 2026-06-08 13:26:57 +08:00
parent ba2504de4a
commit 955c92cff3
2 changed files with 170 additions and 2 deletions

View File

@ -19,7 +19,11 @@
<span class="text-[2.75rem] font-600" v-if="index > 2">{{ index + 1 }}</span> <span class="text-[2.75rem] font-600" v-if="index > 2">{{ index + 1 }}</span>
</template> </template>
<template #name="{ data }"> <template #name="{ data }">
<span class="text-[#C0EEFF] text-[2.75rem]">{{ data.name }}</span> <Tooltip :text="data.name" position="bottom">
<span class="block max-w-[9rem] overflow-hidden text-ellipsis whitespace-nowrap text-[#C0EEFF] text-[2.75rem]">
{{ data.name }}
</span>
</Tooltip>
</template> </template>
<template #total="{data}"> <template #total="{data}">
<span class="text-[#C0EEFF] text-[2.75rem]">{{ data.total }}</span> <span class="text-[#C0EEFF] text-[2.75rem]">{{ data.total }}</span>
@ -47,7 +51,11 @@
<span class="text-[2.75rem] font-600" v-if="index > 2">{{ index + 1 }}</span> <span class="text-[2.75rem] font-600" v-if="index > 2">{{ index + 1 }}</span>
</template> </template>
<template #name="{ data }"> <template #name="{ data }">
<span class="text-[#C0EEFF] text-[2.75rem]">{{ data.name }}</span> <Tooltip :text="data.name" position="bottom">
<span class="block max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-[#C0EEFF] text-[2.75rem]">
{{ data.name }}
</span>
</Tooltip>
</template> </template>
<template #total="{data}"> <template #total="{data}">
<span class="text-[#C0EEFF] text-[2.75rem]">{{ data.total }}</span> <span class="text-[#C0EEFF] text-[2.75rem]">{{ data.total }}</span>
@ -60,6 +68,7 @@
import SvgComponent from "@/components/SvgComponent.vue"; import SvgComponent from "@/components/SvgComponent.vue";
import RankingTable from "@/components/table/RankingTable.vue"; import RankingTable from "@/components/table/RankingTable.vue";
import MobileDrawer from "./MobileDrawer.vue"; import MobileDrawer from "./MobileDrawer.vue";
import Tooltip from "./Tooltip.vue";
const columns = [ const columns = [
{ field: "rank", header: "名次", align: "justify-center", width: "6rem" }, { field: "rank", header: "名次", align: "justify-center", width: "6rem" },

View File

@ -0,0 +1,159 @@
<template>
<span
ref="triggerRef"
class="inline-flex max-w-full min-w-0 align-middle outline-none"
tabindex="0"
@mouseenter="showTip"
@mouseleave="hideTip"
@focus="showTip"
@blur="hideTip"
>
<slot></slot>
</span>
<Teleport to="body">
<Transition
enter-active-class="transition-all duration-150 ease-out"
leave-active-class="transition-all duration-150 ease-in"
enter-from-class="opacity-0 translate-y-[0.25rem]"
leave-to-class="opacity-0 translate-y-[0.25rem]"
>
<div
v-if="visible"
ref="tipRef"
class="fixed z-[9999] max-w-[min(38rem,calc(100vw-2rem))] px-[1.5rem] py-[1rem] text-[#D9F7FF] text-[2rem] leading-[1.25] break-all pointer-events-none border border-[rgba(132,232,255,0.55)] rounded-[0.75rem] bg-[linear-gradient(180deg,rgba(10,58,132,0.96)_0%,rgba(7,35,98,0.98)_100%)] shadow-[0_0_1.5rem_rgba(68,193,239,0.28),inset_0_0_1rem_rgba(68,193,239,0.14)]"
:style="tipStyle"
role="tooltip"
>
<span class="block">{{ text }}</span>
<span
class="absolute h-[0.85rem] w-[0.85rem] rotate-45 border-[rgba(132,232,255,0.55)] border-solid bg-[rgba(7,35,98,0.98)]"
:class="arrowPlacementClass"
></span>
</div>
</Transition>
</Teleport>
</template>
<script lang="ts" setup>
import { computed, nextTick, onBeforeUnmount, reactive, ref } from "vue";
type TooltipPosition = "top" | "bottom" | "left" | "right";
const props = withDefaults(
defineProps<{
text: string;
position?: TooltipPosition;
delay?: number;
}>(),
{
position: "top",
delay: 160,
},
);
const triggerRef = ref<HTMLElement | null>(null);
const tipRef = ref<HTMLElement | null>(null);
const visible = ref(false);
const isListening = ref(false);
const timer = ref<number | null>(null);
const gap = 10;
const viewportPadding = 8;
const tipStyle = reactive({
top: "0px",
left: "0px",
});
const arrowPlacementClass = computed(() => {
const positions: Record<TooltipPosition, string> = {
top: "bottom-[-0.48rem] left-1/2 translate-x-[-50%] border-r border-b",
bottom: "top-[-0.48rem] left-1/2 translate-x-[-50%] border-t border-l",
left: "right-[-0.48rem] top-1/2 translate-y-[-50%] border-t border-r",
right: "left-[-0.48rem] top-1/2 translate-y-[-50%] border-b border-l",
};
return positions[props.position];
});
const clearTimer = () => {
if (timer.value) {
window.clearTimeout(timer.value);
timer.value = null;
}
};
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);
const addPositionListeners = () => {
if (isListening.value) return;
window.addEventListener("scroll", calculatePosition, true);
window.addEventListener("resize", calculatePosition);
isListening.value = true;
};
const removePositionListeners = () => {
if (!isListening.value) return;
window.removeEventListener("scroll", calculatePosition, true);
window.removeEventListener("resize", calculatePosition);
isListening.value = false;
};
const showTip = () => {
if (!props.text) return;
if (visible.value) {
calculatePosition();
return;
}
clearTimer();
timer.value = window.setTimeout(async () => {
timer.value = null;
visible.value = true;
await nextTick();
calculatePosition();
addPositionListeners();
}, props.delay);
};
const hideTip = () => {
clearTimer();
visible.value = false;
removePositionListeners();
};
const calculatePosition = () => {
if (!triggerRef.value || !tipRef.value) return;
const triggerRect = triggerRef.value.getBoundingClientRect();
const tipRect = tipRef.value.getBoundingClientRect();
let top = triggerRect.top - tipRect.height - gap;
let left = triggerRect.left + (triggerRect.width - tipRect.width) / 2;
switch (props.position) {
case "bottom":
top = triggerRect.bottom + gap;
left = triggerRect.left + (triggerRect.width - tipRect.width) / 2;
break;
case "left":
top = triggerRect.top + (triggerRect.height - tipRect.height) / 2;
left = triggerRect.left - tipRect.width - gap;
break;
case "right":
top = triggerRect.top + (triggerRect.height - tipRect.height) / 2;
left = triggerRect.right + gap;
break;
case "top":
default:
break;
}
tipStyle.top = `${clamp(top, viewportPadding, window.innerHeight - tipRect.height - viewportPadding)}px`;
tipStyle.left = `${clamp(left, viewportPadding, window.innerWidth - tipRect.width - viewportPadding)}px`;
};
onBeforeUnmount(() => {
hideTip();
});
</script>