封装输入框组件(适配暗黑模式 & 动态高度)
概述
用户私信详情页面与评论详情页面结构类似。本节完成私信详情页的基础结构,创建 MessageItem 组件,并封装输入框组件以适配暗黑模式和动态高度。
私信详情页结构
页面布局
┌──────────────────────────────────────────────────┐
│ MessageDetail │
│ ┌──────────┬──────────────────────┬────────────┐ │
│ │ 快捷操作 │ 私信列表 │ 用户信息 │ │
│ │ │ ┌──────────────────┐ │ │ │
│ │ [标记] │ │ MessageItem 1 │ │ 头像 │ │
│ │ [删除] │ │ MessageItem 2 │ │ 昵称 │ │
│ │ [置顶] │ │ MessageItem 3 │ │ │ │
│ │ │ └──────────────────┘ │ │ │
│ │ │ ┌──────────────────┐ │ │ │
│ │ │ │ 输入框 (动态高度) │ │ │ │
│ │ │ └──────────────────┘ │ │ │
│ └──────────┴──────────────────────┴────────────┘ │
└──────────────────────────────────────────────────┘
text
路由传参
// 列表页点击详情,携带 ID
const handleMore = (row: MessageRow) => {
router.push({
path: '/messages/detail',
query: { id: row.id },
})
}
// 详情页获取参数
const route = useRoute()
const messageId = computed(() => route.query.id)
typescript
MessageItem 组件
组件创建
components/message/
└── message-item.vue
text
基础结构
<template>
<div class="message-item">
<!-- 与 CommentItem 结构类似 -->
<div class="flex items-start gap-3">
<el-avatar :size="32" :src="data.avatar" />
<div class="flex flex-col">
<span class="text-sm font-medium">{{ data.nickname }}</span>
<p class="text-sm mt-1">{{ data.content }}</p>
<span class="text-xs text-gray-400 mt-1">{{ data.time }}</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
interface MessageItemData {
id: string
avatar: string
nickname: string
content: string
time: string
}
defineProps<{
data: MessageItemData
}>()
</script>
vue
输入框组件封装
核心功能
| 功能 | 实现方式 |
|---|---|
| 暗黑模式适配 | CSS 变量 + Tailwind dark: 前缀 |
| 动态高度 | 监听内容变化自动调整 textarea 高度 |
| 最大高度限制 | max-height: 13rem (52 units) |
<template>
<div class="message-input">
<textarea
ref="textareaRef"
v-model="content"
class="w-full resize-none border rounded-lg p-3
bg-white dark:bg-gray-800
border-gray-300 dark:border-gray-600
text-gray-900 dark:text-gray-100
focus:ring-2 focus:ring-blue-500"
:style="{ height: textareaHeight + 'px', maxHeight: '13rem' }"
placeholder="输入消息..."
@input="adjustHeight"
/>
</div>
</template>
<script setup lang="ts">
const content = ref('')
const textareaRef = ref<HTMLTextAreaElement>()
const textareaHeight = ref(40)
function adjustHeight() {
const el = textareaRef.value
if (!el) return
el.style.height = 'auto'
textareaHeight.value = Math.min(el.scrollHeight, 13 * 16) // 13rem = 208px
}
</script>
vue
关键要点
- 私信详情与评论详情布局类似,复用 CommentItem 的结构思路
- 路由传参通过
router.push携带 ID,详情页用useRoute().query获取 - MessageItem 组件结构与 CommentItem 相似,可抽取公共部分
- 输入框使用
textarea实现动态高度,监听@input事件调整 - 最大高度限制为 13rem,超出后出现滚动条
↑