预览系统
AI-SideChat 提供了现代化的毛玻璃预览功能,让你无需跳转即可查看收藏的完整内容。
悬浮预览
触发方式
鼠标悬停在悬浮坞中的任意收藏条目上,会自动弹出预览窗口。
预览内容
预览窗口显示:
- 问题:完整的用户提问
- 回答:AI 的完整回答(HTML 格式)
- 格式:保留原始格式(代码块、列表、粗体等)
- 代码复制:代码块带复制按钮
视觉设计
- 毛玻璃效果:
backdrop-filter: blur(10px) - 半透明背景:
background: rgba(255, 255, 255, 0.9) - 阴影:
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1) - 圆角:
border-radius: 12px
钉住功能
如何钉住
- 悬停显示预览窗口
- 点击右上角的 📌 图标
- 预览窗口会固定在屏幕上
钉住后的特性
- 持久显示:不会因为鼠标移开而消失
- 可拖拽:点击标题栏拖拽移动
- 独立窗口:可以边看预览边操作其他内容
- 关闭按钮:点击 ❌ 关闭
拖拽移动
实现方式
javascript
let isDragging = false
let offsetX, offsetY
titleBar.addEventListener('mousedown', (e) => {
isDragging = true
offsetX = e.clientX - preview.offsetLeft
offsetY = e.clientY - preview.offsetTop
})
document.addEventListener('mousemove', (e) => {
if (isDragging) {
preview.style.left = (e.clientX - offsetX) + 'px'
preview.style.top = (e.clientY - offsetY) + 'px'
}
})
document.addEventListener('mouseup', () => {
isDragging = false
})拖拽体验
- 平滑移动:实时跟随鼠标
- 边界限制:不会拖出屏幕
- 视觉反馈:拖拽时光标变化
代码复制
自动检测
预览窗口会自动识别代码块:
javascript
const codeBlocks = preview.querySelectorAll('pre code')
codeBlocks.forEach(block => {
addCopyButton(block)
})复制按钮
每个代码块右上角会显示复制按钮:
- 默认:📋 图标
- 悬停:高亮显示
- 点击后:显示 ✅,提示"已复制"
- 2 秒后:恢复原状
实现代码
javascript
function addCopyButton(codeBlock) {
const button = document.createElement('button')
button.textContent = '复制'
button.onclick = () => {
navigator.clipboard.writeText(codeBlock.textContent)
button.textContent = '已复制 ✅'
setTimeout(() => {
button.textContent = '复制'
}, 2000)
}
codeBlock.parentElement.appendChild(button)
}关键词高亮
搜索时高亮
当在搜索框中输入关键词时:
- 预览窗口中的匹配文本会高亮
- 使用黄色背景标记
- 便于快速找到相关内容
高亮实现
javascript
function highlightKeyword(text, keyword) {
const regex = new RegExp(keyword, 'gi')
return text.replace(regex, match => {
return `<mark>${match}</mark>`
})
}样式
css
mark {
background-color: #fff59d;
color: #000;
padding: 2px 4px;
border-radius: 2px;
}响应式设计
位置计算
预览窗口会智能选择显示位置:
- 默认:鼠标右侧
- 右侧空间不足:显示在左侧
- 底部空间不足:向上偏移
javascript
function calculatePosition(mouseX, mouseY) {
const previewWidth = 400
const previewHeight = 600
let left = mouseX + 20
let top = mouseY - 100
if (left + previewWidth > window.innerWidth) {
left = mouseX - previewWidth - 20
}
if (top + previewHeight > window.innerHeight) {
top = window.innerHeight - previewHeight - 20
}
return { left, top }
}移动端适配
规划中
移动端版本将采用全屏预览模式,提供更好的阅读体验。
性能优化
懒加载
- 只在悬停时才渲染预览内容
- 避免一次性渲染所有收藏的预览
虚拟 DOM
- 使用 innerHTML 而非逐个创建元素
- 提高大内容的渲染速度
防抖处理
javascript
let hoverTimeout
element.addEventListener('mouseenter', () => {
hoverTimeout = setTimeout(() => {
showPreview()
}, 300)
})
element.addEventListener('mouseleave', () => {
clearTimeout(hoverTimeout)
})使用技巧
💡 技巧 1:快速浏览
悬停在多个收藏上快速浏览内容,找到需要的那一条。
💡 技巧 2:对比查看
钉住多个预览窗口,对比不同 AI 的回答。
💡 技巧 3:边看边操作
钉住预览窗口,边看内容边在编辑器中编写代码。
💡 技巧 4:复制代码
直接从预览窗口复制代码,无需跳转到原页面。
