HeliaShare 的 UI 设计与交互实现
今天分享 HeliaShare 的用户界面设计和关键交互实现细节。
设计原则
1. 简洁至上
IPFS 概念对普通用户来说已经比较复杂,UI 应该尽可能简洁:
- 隐藏技术细节: 用户不需要知道什么是 CID、DAG、DHT
- 清晰的反馈: 每个操作都有明确的状态提示
- 渐进式披露: 高级功能放在次要位置
2. 实时反馈
网络操作通常较慢,实时反馈能提升用户体验:
// 上传进度
async function handleFileUpload(file) {
showProgress(0)
const arrayBuffer = await file.arrayBuffer()
showProgress(30)
const cid = await fs.addBytes(new Uint8Array(arrayBuffer))
showProgress(70)
await helia.pins.add(cid)
showProgress(100)
}
3. 容错设计
网络不稳定是常态,应用需要优雅处理错误:
try {
const cid = await fs.addBytes(data)
} catch (error) {
showError('上传失败: ' + error.message)
// 提供重试选项
showRetryButton()
}
关键交互实现
拖拽上传
const uploadZone = document.getElementById('uploadZone')
// 拖拽进入
uploadZone.addEventListener('dragover', (e) => {
e.preventDefault()
uploadZone.classList.add('dragover')
})
// 拖拽离开
uploadZone.addEventListener('dragleave', () => {
uploadZone.classList.remove('dragover')
})
// 放置文件
uploadZone.addEventListener('drop', (e) => {
e.preventDefault()
uploadZone.classList.remove('dragover')
const files = e.dataTransfer.files
if (files.length > 0) {
handleFileUpload(files[0])
}
})
CSS 样式:
.upload-zone {
border: 2px dashed var(--border);
transition: all 0.3s;
}
.upload-zone.dragover {
border-color: var(--success);
background: rgba(34, 197, 94, 0.1);
}
实时进度条
获取文件时的进度显示是用户体验的关键:
async function fetchFile(cidString) {
// 显示进度面板
showProgressPanel()
let receivedBytes = 0
const chunks = []
// 定期更新进度
const progressInterval = setInterval(() => {
updateProgress(receivedBytes)
}, 500)
// 流式下载
for await (const chunk of fs.cat(cid)) {
chunks.push(chunk)
receivedBytes += chunk.length
}
clearInterval(progressInterval)
completeProgress()
}
进度条样式:
.fetch-progress-bar {
width: 100%;
height: 12px;
background: var(--bg-hover);
border-radius: 6px;
overflow: hidden;
}
.fetch-progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary), var(--success));
width: 0%;
transition: width 0.3s ease;
}
文件预览
根据文件类型显示不同的预览:
function showPreview(file) {
const url = URL.createObjectURL(file.blob)
if (file.type.startsWith('image/')) {
return `<img src="${url}" class="preview-image">`
}
else if (file.type.startsWith('video/')) {
return `<video src="${url}" controls></video>`
}
else if (file.type.startsWith('text/')) {
// 读取文本内容
return `<pre>${escapeHtml(text)}</pre>`
}
else {
return `<div>无法预览,请下载查看</div>`
}
}
通知系统
非阻塞式通知,避免打断用户操作:
function showNotification(message, type = 'info') {
const notification = document.createElement('div')
notification.className = `notification ${type}`
notification.textContent = message
document.body.appendChild(notification)
// 3秒后自动消失
setTimeout(() => {
notification.remove()
}, 3000)
}
CSS 动画:
.notification {
position: fixed;
bottom: 20px;
right: 20px;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
响应式设计
确保在移动设备上也能良好使用:
@media (max-width: 600px) {
.container {
padding: 12px;
}
.input-group {
flex-direction: column;
}
.sharing-controls {
flex-direction: column;
}
.sharing-controls button {
width: 100%;
}
}
暗色主题
使用深色主题减少眼部疲劳,同时符合技术工具的调性:
:root {
--bg: #0f172a; /* 深蓝黑背景 */
--bg-card: #1e293b; /* 卡片背景 */
--text: #f1f5f9; /* 主文字 */
--text-muted: #94a3b8; /* 次要文字 */
--primary: #3b82f6; /* 主色调 */
--success: #22c55e; /* 成功 */
--warning: #f59e0b; /* 警告 */
--danger: #ef4444; /* 错误 */
}
性能优化
虚拟滚动
当历史记录很多时,使用虚拟滚动优化性能:
// 只渲染可见区域的项目
function renderVisibleItems(items, container) {
const visibleItems = items.slice(startIndex, endIndex)
container.innerHTML = visibleItems.map(renderItem).join('')
}
防抖处理
搜索输入等频繁触发的事件需要防抖:
function debounce(fn, delay) {
let timer = null
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
下一篇预告
下一篇将分享部署和运维经验,包括:
- 静态托管方案对比
- HTTPS 配置要点
- 性能监控和优化
你对哪个交互实现最感兴趣?或者有什么更好的设计方案?欢迎讨论。