195 lines
4.0 KiB
Vue
195 lines
4.0 KiB
Vue
<template>
|
|
<teleport to="body">
|
|
<transition name="fade">
|
|
<div
|
|
v-if="isVisible"
|
|
class="im-hover-card"
|
|
:style="cardStyle"
|
|
@mouseenter="clearTimer"
|
|
@mouseleave="hide"
|
|
>
|
|
<div class="card-inner">
|
|
<div class="user-profile">
|
|
<div class="info-text">
|
|
<h4 class="nickname">{{ currentUser.name }}</h4>
|
|
<p class="detail-item">
|
|
<span class="label">微信号:</span>
|
|
<span class="value">{{ currentUser.id }}</span>
|
|
</p>
|
|
<p class="detail-item">
|
|
<span class="label">地 区:</span>
|
|
<span class="value">{{ currentUser.region || '未知' }}</span>
|
|
</p>
|
|
</div>
|
|
<img :src="currentUser.avatar" class="avatar-square" />
|
|
</div>
|
|
|
|
<div class="user-bio">
|
|
<p class="bio-text">{{ currentUser.bio || '暂无签名' }}</p>
|
|
</div>
|
|
|
|
<div class="card-footer">
|
|
<button class="action-btn primary" @click="onChat">发消息</button>
|
|
<button v-if="!currentUser.isFriend" class="action-btn secondary" @click="onAdd">添加好友</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</teleport>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive } from 'vue';
|
|
|
|
const isVisible = ref(false);
|
|
const currentUser = ref({});
|
|
const cardStyle = reactive({
|
|
position: 'fixed',
|
|
top: '0px',
|
|
left: '0px'
|
|
});
|
|
|
|
let timer = null;
|
|
|
|
const show = (el, data) => {
|
|
clearTimer();
|
|
currentUser.value = data;
|
|
|
|
const rect = el.getBoundingClientRect();
|
|
// IM 习惯:通常在头像右侧或下方弹出
|
|
// 这里设置为在头像中心水平对齐,下方弹出
|
|
cardStyle.top = `${rect.bottom + 8}px`;
|
|
cardStyle.left = `${rect.left}px`;
|
|
|
|
isVisible.value = true;
|
|
};
|
|
|
|
const hide = () => {
|
|
timer = setTimeout(() => {
|
|
isVisible.value = false;
|
|
}, 300);
|
|
};
|
|
|
|
const clearTimer = () => {
|
|
if (timer) clearTimeout(timer);
|
|
};
|
|
|
|
const onAdd = () => {
|
|
console.log('申请添加好友:', currentUser.value.id);
|
|
// 这里写你的逻辑
|
|
};
|
|
|
|
const onChat = () => {
|
|
console.log('跳转聊天窗口:', currentUser.value.id);
|
|
isVisible.value = false;
|
|
};
|
|
|
|
defineExpose({ show, hide });
|
|
</script>
|
|
|
|
<style scoped>
|
|
.im-hover-card {
|
|
z-index: 9999;
|
|
width: 280px;
|
|
background: #ffffff;
|
|
border-radius: 4px; /* IM 通常是小圆角或直角 */
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
|
|
border: 1px solid #ebeef5;
|
|
color: #333;
|
|
font-family: "Microsoft YaHei", sans-serif;
|
|
}
|
|
|
|
.card-inner {
|
|
padding: 20px;
|
|
}
|
|
|
|
/* 头部布局:文字在左,头像在右(典型微信名片风) */
|
|
.user-profile {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.nickname {
|
|
margin: 0 0 10px 0;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: #000;
|
|
}
|
|
|
|
.detail-item {
|
|
margin: 4px 0;
|
|
font-size: 13px;
|
|
display: flex;
|
|
}
|
|
|
|
.detail-item .label {
|
|
color: #999;
|
|
width: 55px;
|
|
}
|
|
|
|
.detail-item .value {
|
|
color: #555;
|
|
}
|
|
|
|
.avatar-square {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 4px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
/* 签名区 */
|
|
.user-bio {
|
|
padding: 15px 0;
|
|
border-top: 1px solid #f2f2f2;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.bio-text {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
color: #888;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* 底部按钮:去掉花哨渐变,改用纯色或文字链接感 */
|
|
.card-footer {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
padding-top: 10px;
|
|
border-top: 1px solid #f2f2f2;
|
|
}
|
|
|
|
.action-btn {
|
|
background: transparent;
|
|
border: none;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
padding: 8px 12px;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.action-btn.primary {
|
|
color: #576b95; /* 经典的微信蓝/链接色 */
|
|
}
|
|
|
|
.action-btn.primary:hover {
|
|
color: #3e4d6d;
|
|
}
|
|
|
|
.action-btn.secondary {
|
|
color: #576b95;
|
|
}
|
|
|
|
/* 动画:简单的淡入 */
|
|
.fade-enter-active, .fade-leave-active {
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
.fade-enter-from, .fade-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style> |