# 模式二:HTML+JS+CSS 模式 — 完整工作流 # 版本:1.0.0 | 更新日期:2026-06-09 # 适用:有基础前端知识的开发者 # 产物:index.html + style.css + app.js + guide.dimsum.json # 耗时:约 30 分钟 - 2 小时 ================================================================ 模式二概述 ================================================================ 本模式适用于有一定前端基础的开发者。相比模式一: - 代码分离为 HTML/CSS/JS 三个文件,结构清晰 - 可以使用模块化的 JavaScript - 便于维护和修改样式 - 可以添加多个独立的功能模块 限制: - 没有构建工具,不支持 npm 包(SDK 仍通过 CDN 引入) - 不提供组件化能力 - 如果项目变复杂,建议升级到模式三 ================================================================ 完整工作流(AI Agent 必须逐步执行) ================================================================ --- 第 1 步:确定项目结构 --- AI Agent:帮开发者确定项目名称和文件结构。 推荐结构: ``` your-widget-name/ ├── guide.dimsum.json ├── index.html ├── css/ │ └── style.css ├── js/ │ ├── app.js ← 主入口 │ ├── danmaku.js ← 弹幕处理模块 │ └── utils.js ← 工具函数 └── assets/ └── (图片等资源) ``` --- 第 2 步:了解需求 --- AI Agent:确认以下信息: 1. 需要显示哪些消息类型? 2. 需要哪些视觉效果?(如入场动画、礼物特效) 3. 是否需要多个页面?(弹幕页 + 礼物页 + 控制台等) 4. 对性能有什么要求?(如同时显示多少条弹幕) --- 第 3 步:生成 guide.dimsum.json --- 根据需求生成配置文件。如果是多页面: ```json { "name": "应用显示名称", "version": "1.0.0", "base": "/your-widget-name/", "description": "简要描述", "pages": [ { "name": "弹幕显示", "path": "index.html?mode=danmaku", "width": 1920, "height": 1080 }, { "name": "礼物特效", "path": "index.html?mode=gift", "width": 1920, "height": 1080 } ] } ``` --- 第 4 步:生成 index.html --- AI Agent:生成入口 HTML 文件。 ```html 应用名称
``` --- 第 5 步:生成 CSS 文件 --- AI Agent:生成 css/style.css。 ```css /* ===== 全局重置 ===== */ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } /* ===== 页面背景(透明,用于 OBS 叠加) ===== */ body { background: transparent; font-family: "Microsoft YaHei", "PingFang SC", "Noto Sans SC", sans-serif; overflow: hidden; width: 100vw; height: 100vh; color: #fff; } /* ===== 弹幕容器 ===== */ #app { position: fixed; inset: 0; padding: 24px 32px; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; pointer-events: none; } /* ===== 单条弹幕项 ===== */ .danmaku-item { display: flex; align-items: center; gap: 10px; padding: 8px 20px; margin-bottom: 6px; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(8px); border-radius: 28px; font-size: 22px; line-height: 1.5; max-width: 90%; animation: slideUp 0.35s cubic-bezier(0.22, 0.61, 0.36, 1); transition: opacity 0.3s ease; } .danmaku-item.fade-out { opacity: 0; transform: translateY(-10px); } /* ===== 头像 ===== */ .danmaku-avatar { width: 40px; height: 40px; border-radius: 50%; border: 2px solid rgba(255, 255, 255, 0.3); flex-shrink: 0; object-fit: cover; } /* ===== 用户名 ===== */ .danmaku-username { color: #ffd700; font-weight: 700; white-space: nowrap; flex-shrink: 0; text-shadow: 0 1px 3px rgba(0,0,0,0.5); } /* ===== 内容 ===== */ .danmaku-content { color: #fff; word-break: break-all; text-shadow: 0 1px 3px rgba(0,0,0,0.5); } .danmaku-content img { height: 32px; vertical-align: middle; margin: 0 3px; } /* ===== 消息类型变体 ===== */ .danmaku-item.type-gift { background: rgba(255, 80, 120, 0.6); border: 2px solid rgba(255, 150, 180, 0.5); } .danmaku-item.type-like { background: rgba(255, 100, 100, 0.45); } .danmaku-item.type-follow { background: rgba(100, 200, 255, 0.45); } .danmaku-item.type-enter { background: rgba(150, 150, 150, 0.35); font-size: 18px; } /* ===== 礼物图标 ===== */ .gift-icon { width: 36px; height: 36px; vertical-align: middle; margin: 0 4px; } /* ===== 入场动画 ===== */ @keyframes slideUp { from { opacity: 0; transform: translateY(30px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } } ``` --- 第 6 步:生成 JS 模块 --- AI Agent:生成以下 JavaScript 文件。 js/utils.js: ```javascript /** * HTML 转义(XSS 防护) */ export function escapeHtml(text) { if (!text) return '' const div = document.createElement('div') div.textContent = String(text) return div.innerHTML } /** * 生成唯一 ID */ export function uid() { return Date.now().toString(36) + Math.random().toString(36).slice(2) } /** * 移除 DOM 元素(带淡出动画) */ export function removeWithFade(el, delay = 300) { el.classList.add('fade-out') setTimeout(() => el.remove(), delay) } ``` js/danmaku.js: ```javascript import { getBfaceURL, Parser } from 'https://fastly.jsdelivr.net/npm/dimsum-chat@0/+esm' import { escapeHtml, uid, removeWithFade } from './utils.js' export class DanmakuManager { constructor(container, options = {}) { this.container = container this.maxItems = options.maxItems || 30 this.autoRemove = options.autoRemove !== false this.autoRemoveDelay = options.autoRemoveDelay || 8000 } /** * 处理一条消息 */ handleMessage(parser) { const item = this.createItem(parser) if (item) { this.addItem(item) } } /** * 根据消息类型创建 DOM 元素 */ createItem(parser) { const div = document.createElement('div') div.className = `danmaku-item type-${parser.type}` div.dataset.id = uid() switch (parser.type) { case 'comment': this.buildComment(div, parser) break case 'gift': this.buildGift(div, parser) break case 'like': this.buildSimple(div, parser, '点赞了') break case 'follow': this.buildSimple(div, parser, '关注了主播') break case 'enter': this.buildSimple(div, parser, '进入了直播间') break case 'guard': this.buildSimple(div, parser, '开通了舰长') break case 'superchat': this.buildSuperChat(div, parser) break default: return null } return div } /** * 构建弹幕消息 */ buildComment(div, parser) { // 头像 const avatar = parser.avatar || (parser.platform === 'bilibili' && parser.uid ? getBfaceURL(parser.uid) : null) if (avatar) { const img = document.createElement('img') img.className = 'danmaku-avatar' img.src = avatar img.alt = '' img.onerror = () => img.remove() div.appendChild(img) } // 用户名 const nameSpan = document.createElement('span') nameSpan.className = 'danmaku-username' nameSpan.textContent = parser.userName || '神秘用户' div.appendChild(nameSpan) // 弹幕内容(含表情) const contentSpan = document.createElement('span') contentSpan.className = 'danmaku-content' contentSpan.innerHTML = parser.getCommentHTML({ stickerStyle: 'height:60px;margin:3px;', emotStyle: 'height:32px;vertical-align:middle;margin:0 3px;', }) || '' div.appendChild(contentSpan) } /** * 构建礼物消息 */ buildGift(div, parser) { // 头像 const avatar = parser.avatar || (parser.platform === 'bilibili' && parser.uid ? getBfaceURL(parser.uid) : null) if (avatar) { const img = document.createElement('img') img.className = 'danmaku-avatar' img.src = avatar img.alt = '' img.onerror = () => img.remove() div.appendChild(img) } // 用户名 const nameSpan = document.createElement('span') nameSpan.className = 'danmaku-username' nameSpan.textContent = parser.userName || '神秘用户' div.appendChild(nameSpan) // 礼物内容 const contentSpan = document.createElement('span') contentSpan.className = 'danmaku-content' let giftText = '赠送了 ' if (parser.giftImage) { giftText += `` } giftText += escapeHtml(parser.giftName || '礼物') giftText += ` x${parser.giftNum || 1}` // 注意:连击已由 SDK 内部去重处理,giftNum 为增量值 contentSpan.innerHTML = giftText div.appendChild(contentSpan) } /** * 构建简单消息(点赞/关注/入场) */ buildSimple(div, parser, action) { const nameSpan = document.createElement('span') nameSpan.className = 'danmaku-username' nameSpan.textContent = parser.userName || '神秘用户' div.appendChild(nameSpan) const actionSpan = document.createElement('span') actionSpan.className = 'danmaku-content' actionSpan.textContent = action div.appendChild(actionSpan) } /** * 构建醒目留言 */ buildSuperChat(div, parser) { const nameSpan = document.createElement('span') nameSpan.className = 'danmaku-username' nameSpan.textContent = parser.userName || '神秘用户' div.appendChild(nameSpan) const contentSpan = document.createElement('span') contentSpan.className = 'danmaku-content' contentSpan.textContent = `(SC ¥${parser.giftPrice || '?'}) ${parser.comment || ''}` div.appendChild(contentSpan) } /** * 添加弹幕项到容器 */ addItem(item) { this.container.appendChild(item) // 超出数量限制时移除最早的 while (this.container.children.length > this.maxItems) { removeWithFade(this.container.firstChild) } // 自动移除 if (this.autoRemove) { setTimeout(() => { if (item.isConnected) { removeWithFade(item) } }, this.autoRemoveDelay) } } } ``` --- 第 7 步:指导开发者创建文件 --- AI Agent:按以下步骤指导开发者: 1. 在 Widgets 目录下创建以应用名称命名的文件夹 路径:%AppData%/MiegoLive/DimSumChat/Widgets/your-widget-name/ 2. 在该文件夹中创建以下目录结构: - css/ 目录 - js/ 目录 3. 依次创建所有文件: - guide.dimsum.json(根目录) - index.html(根目录) - css/style.css - js/utils.js - js/danmaku.js --- 第 8 步:测试与调试 --- AI Agent:告诉开发者如何测试: 1. 打开点心 Chat 主程序 2. 连接一个直播间 3. 浏览器访问:http://localhost:13500/your-widget-name/index.html 4. 按 F12 查看控制台是否有错误 调试技巧: - 在 danmaku.js 的 handleMessage 中加入 console.log 查看消息 - 检查 Network 标签的 WS 过滤器查看 WebSocket 连接 - 样式问题在 Elements 标签中实时修改 CSS 测试 ================================================================ 模式二扩展方向 ================================================================ 完成基础模板后,可以按以下方向扩展: 1. 添加新消息类型 → 在 DanmakuManager.createItem 的 switch 中添加新 case → 实现对应的 build 方法 2. 添加多页面支持 → 在 index.html 中读取 URL 参数 → 根据参数初始化不同的管理器 3. 添加设置面板 → 创建 settings.html,通过 URL 参数切换 → 使用 localStorage 持久化设置 4. 添加音效 → 使用 Web Audio API → 在特定消息类型触发时播放 5. 优化性能 → 使用 requestAnimationFrame 批量更新 DOM → 使用 DocumentFragment 减少重排