Tailwind CSS 实战:基于 Kooboo 构建 AI 对话框页面(六):图片上传功能
在 《Tailwind CSS 实战:基于 Kooboo 构建 AI 对话框页面(五)》 中,完成了语音交互功能的优化。本文作为该系列教程的第六篇,将聚焦于图片上传功能的开发。通过集成图片上传与预览能力,我们将进一步完善 AI 对话框的交互体验。效果如下:
一、功能需求分析
本次开发需实现以下核心功能:
- 图片上传入口:在语音识别按钮旁添加图片上传图标,支持点击选择本地图片。
- 文件类型与大小限制:仅允许上传图片文件(如 PNG/JPG),限制文件大小不超过 5MB。
- 实时预览:选择图片后,在消息气泡中显示图片预览。
- 图文混合发送:支持同时发送文本与图片,保持原有消息交互逻辑。
二、HTML部分
1. 样式调整:在语音识别按钮旁添加图片上传图标
<style>.image-upload-button {position: absolute;right: 8px; /* 调整到语音按钮右侧 */top: 50%;transform: translateY(-50%);width: 32px;height: 32px;display: flex;align-items: center;justify-content: center;cursor: pointer;color: var(--text-secondary);background: transparent;border: none;z-index: 10;}.image-upload-button:hover {color: var(--accent-color);}/* 输入框宽度调整(为上传按钮腾出空间) */.message-input {padding-left: 40px !important; /* 原有左侧语音按钮 */padding-right: 40px !important; /* 新增右侧上传按钮 */}/* 图片预览样式 */.image-preview {max-width: 200px;max-height: 200px;border-radius: 8px;margin-top: 8px;object-fit: contain;}</style>
2. 图标添加
<body><!-- ... 原有body内容 ... --><!-- 输入区域 --><div class="bg-[var(--bg-primary)] p-4 border-t border-[var(--border-color)]"><div class="flex space-x-2"><!-- 输入框包装器 --><div class="input-wrapper relative"> <!-- 添加relative定位 --><button id="voiceButton" class="voice-button"><i class="fa fa-microphone"></i></button><!-- 新增图片上传按钮 --><button id="imageUploadButton" class="image-upload-button"><i class="fa fa-image"></i> <!-- Font Awesome图片图标 --></button><input id="messageInput"type="text" placeholder="输入消息..." class="message-input flex-1 w-full p-2 border border-[var(--border-color)] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 bg-[var(--bg-secondary)] text-[var(--text-primary)]"></div><!-- ... 原有发送按钮 ... --></div></div><!-- 新增文件上传隐藏输入 --><input type="file" id="imageInput" accept="image/*" style="display: none;">
三、图片上传功能的完整实现(JavaScript 逻辑解析)
1. 核心变量与 DOM 元素获取
在 DOMContentLoaded
事件中初始化图片上传相关元素:
// 图片上传相关元素
const imageUploadButton = document.getElementById('imageUploadButton');
const imageInput = document.getElementById('imageInput');
imageUploadButton
:显示在输入框右侧的图片上传图标按钮imageInput
:隐藏的文件选择输入框,通过accept="image/*"
限制仅图片类型
2. 图片上传入口交互
通过点击图标按钮触发文件选择:
// 图片上传按钮点击事件
imageUploadButton.addEventListener('click', () => {imageInput.click(); // 触发隐藏的文件选择器
});
交互逻辑:点击图标时,通过 click()
方法模拟 input[type="file"]
的点击行为,唤起系统文件选择窗口
3. 文件验证与预览逻辑
在 imageInput
的 change
事件中处理文件选择:
// 图片选择事件
imageInput.addEventListener('change', (e) => {const file = e.target.files[0];if (!file) return; // 未选择文件时退出// 验证图片类型和大小const isImage = file.type.startsWith('image/');if (!isImage) {alert('请选择有效的图片文件');return;}const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5MBif (file.size > MAX_IMAGE_SIZE) {alert(`图片大小不能超过 ${MAX_IMAGE_SIZE / (1024 * 1024)}MB`);return;}// 预览图片并发送消息const reader = new FileReader();reader.onload = (event) => {const imagePreview = document.createElement('img');imagePreview.className = 'image-preview'; // 应用 Tailwind 预览样式imagePreview.src = event.target.result; // 将文件转为 Base64 预览// 构建包含图片的用户消息const userMessageHtml = `<div class="flex items-start space-x-2 justify-end"><div class="max-w-[70%]"><div class="bg-blue-600 text-white p-4 rounded-lg rounded-tr-none shadow-sm"><div>${messageInput.value}</div> <!-- 保留输入框文本(可选) -->${imagePreview.outerHTML} <!-- 插入图片预览 --><span class="text-xs text-blue-200 mt-1 block">${getCurrentTime()}</span></div></div><div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center"><span class="text-white">我</span></div></div>`;// 将消息添加到对话容器messageContainer.insertAdjacentHTML('beforeend', userMessageHtml);messageInput.value = ''; // 清空输入框scrollToBottom(); // 滚动到最新消息// 模拟 AI 回复(可替换为真实接口调用)setTimeout(() => {addAIResponse("我看到您上传的图片了。目前我还不能识别图片中的文字,不过这是我未来的功能之一!");}, 1000);};reader.readAsDataURL(file); // 异步读取文件内容imageInput.value = ''; // 重置文件输入,允许重复选择
});
4. 关键技术点解析
(1) 文件类型验证
- 原理:通过
file.type
获取文件的 MIME 类型,判断是否以image/
开头 - 支持的图片类型:包括
image/jpeg
、image/png
、image/gif
等常见格式
(2) 文件大小验证
- 单位转换:
5 * 1024 * 1024
表示 5MB(1MB = 1024KB = 1024×1024B) - 用户提示:将文件大小转换为 MB 格式显示,提升可读性
(3) 图片预览实现
FileReader
API:readAsDataURL(file)
:将文件读取为 Base64 格式的 URLonload
回调:在文件读取完成后执行,避免阻塞主线程
- DOM 操作:动态创建
<img>
元素并设置src
属性,实现无刷新预览
(4) 消息气泡布局
- Tailwind CSS 样式:
flex items-start
:垂直方向顶部对齐max-w-[70%]
:限制消息气泡最大宽度bg-blue-600
:用户消息背景色rounded-lg shadow-sm
:添加圆角和阴影提升层次感
- 图文混合逻辑:通过
${messageInput.value}
保留输入框文本,实现文本与图片混合发送
四、功能测试与常见问题
1. 测试用例
操作步骤 | 预期结果 |
---|---|
点击图片图标选择非图片文件 | 弹出提示 “请选择有效的图片文件” |
选择超过 5MB 的图片文件 | 弹出提示 “图片大小不能超过 5MB” |
选择正常图片文件 | 消息气泡中显示图片预览,AI 回复 “我看到你上传的图片了...” |
输入文本并选择图片 | 消息气泡中同时显示文本和图片,文本在上、图片在下 |
五、总结
-
图标添加:
- 使用 Font Awesome 的
fa-image
图标(需确保 Font Awesome 已正确引入) - 按钮位于输入框右侧,与左侧语音按钮对称
- 使用 Font Awesome 的
-
样式调整:
- 输入框左右两侧添加内边距,为两个按钮腾出空间
- 定义图片预览样式,支持最大 200px 显示区域
- 上传按钮悬停时显示强调色
-
功能实现:
- 点击图片图标触发隐藏的文件选择输入
- 支持 JPG/PNG 等常见图片格式(通过
accept="image/*"
控制) - 上传后在消息气泡中显示图片预览
- 保留原有文本输入内容,支持图文混合消息
-
交互优化:
- 图片上传后自动滚动到消息底部
- 保持原有语音识别按钮的交互逻辑不变
- 文件输入框隐藏处理,保持界面整洁