# BC-M-CHANNEL-001-JZ · DEV-010桔子 · 用户频道动态渲染引擎 · 环节0~1(SPA路由+模块动态加载) --- ## 一、广播头 · 任务定位 --- ## 二、执行环境声明 | 项目 | 值 | | --- | --- | | **操作系统** | macOS | | **编辑器** | nano(终端直接编辑) | | **技术栈** | 纯HTML + CSS + JavaScript(无框架) | | **模块目录** | `modules/m-channel/` | | **本地路径** | `/Users/chenshujun/Desktop/guanghulab/modules/m-channel/` | | **Git** | juzi0412 · 已配置 · push已连通 | --- ## 三、凭证注入(系统自动·直接使用) --- ## 四、任务目标 ### 环节0 · SPA路由框架搭建 **什么是SPA?** 你之前做的每个模块(M06、M08、M11)都是独立的HTML文件,打开一个就是一个页面。SPA的意思是:**只有一个HTML文件**,里面有一个「内容区」,点击不同链接时,JavaScript把内容区里的东西换掉,但页面本身不刷新。 就像换电视频道——电视机(页面框架)不变,只是频道(内容)在切换。 **Step 0-1 · 创建目录结构** ```bash cd /Users/chenshujun/Desktop/guanghulab mkdir -p modules/m-channel/pages cd modules/m-channel ``` **Step 0-2 · 创建SPA主页(index.html)** ```bash nano index.html ``` 写入以下内容: ```html 光湖频道引擎 · M-CHANNEL
``` **Step 0-3 · 创建路由器(channel-router.js)** ```bash nano channel-router.js ``` 写入以下内容: ```jsx /** * 光湖频道路由器 · Channel Router v1.0 * 功能:监听URL hash变化 → 动态加载对应页面内容 */ const ChannelRouter = { routes: {}, currentRoute: null, // 注册路由:告诉路由器「这个路径对应这个页面」 register: function(path, handler) { this.routes[path] = handler; }, // 导航到指定路径 navigate: function(path) { window.location.hash = '#' + path; }, // 解析当前URL的hash部分 getRoute: function() { var hash = window.location.hash || '#/home'; return hash.replace('#', ''); }, // 渲染页面:找到对应路由的handler,执行它 render: function() { var route = this.getRoute(); var view = document.getElementById('route-view'); var routeDisplay = document.getElementById('current-route'); if (this.routes[route]) { // 找到路由 → 执行对应的渲染函数 this.currentRoute = route; this.routes[route](view); routeDisplay.textContent = '当前路由:' + route; // 更新导航栏高亮 this.updateNavHighlight(route); } else { // 没找到 → 显示404 view.innerHTML = '

404

页面不存在

回到首页
'; routeDisplay.textContent = '当前路由:404'; } }, // 更新导航栏高亮状态 updateNavHighlight: function(route) { var links = document.querySelectorAll('.nav-link'); for (var i = 0; i < links.length; i++) { var linkRoute = links[i].getAttribute('data-route'); if (route.indexOf(linkRoute) !== -1) { links[i].classList.add('active'); } else { links[i].classList.remove('active'); } } }, // 启动路由器 start: function() { var self = this; // 监听hash变化事件 window.addEventListener('hashchange', function() { self.render(); }); // 首次加载也要渲染 self.render(); } }; ``` **Step 0-4 · 创建应用入口(app.js)** ```bash nano app.js ``` 写入以下内容: ```jsx /** * 光湖频道引擎 · App Entry v1.0 * 注册所有路由 → 启动路由器 */ // ====== 注册路由 ====== // 首页 ChannelRouter.register('/home', function(view) { view.innerHTML = '\
\

🌊 欢迎来到光湖

\

语言驱动操作系统 · 你说话,系统做事

\
\ \
\
\
10+功能模块
\
12开发者
\
v1.0系统版本
\
\
'; }); // 用户频道(环节1会在这里加模块动态加载) ChannelRouter.register('/channel', function(view) { view.innerHTML = '\
\
\

📺 我的频道

\

这里是你的专属空间,所有模块都在这里

\
\
\
\ 📋\ 工单管理\ M06\
\
\ 📊\ 数据统计\ M08\
\
\ 🎨\ 风格组件库\ M11\
\
\ ✍️\ 码字工作台\ M16\
\
\ 🎬\ 动态漫\ M17\
\
\ \ 更多模块\ ...\
\
\
'; }); // 关于页面 ChannelRouter.register('/about', function(view) { view.innerHTML = '\
\

关于光湖

\

光湖是一个语言驱动的操作系统平台。

\

用户全程不需要点菜单,只需要跟人格体说话。

\

人格体理解你的意图 → 系统动态渲染对应模块 → 你感觉整个网站只有你一个人。

\
\

技术栈

\ \
\
'; }); // ====== 启动 ====== ChannelRouter.start(); console.log('🌊 光湖频道引擎启动完成'); ``` **Step 0-5 · 创建样式表(channel-style.css)** ```bash nano channel-style.css ``` 写入以下内容: ```css /* ====== 光湖频道引擎样式 · M-CHANNEL v1.0 ====== */ * { margin: 0; padding: 0; box-sizing: border-box; } :root { --primary: #2563eb; --primary-hover: #1d4ed8; --bg: #0f172a; --bg-card: #1e293b; --bg-nav: #1e293b; --text: #f1f5f9; --text-muted: #94a3b8; --border: #334155; --accent: #38bdf8; --radius: 12px; --transition: 0.3s ease; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; } #app { display: flex; flex-direction: column; min-height: 100vh; } /* ====== 导航栏 ====== */ #main-nav { display: flex; align-items: center; justify-content: space-between; padding: 0 24px; height: 60px; background: var(--bg-nav); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 100; } .nav-brand { font-size: 1.25rem; font-weight: 700; color: var(--accent); } .nav-links { display: flex; gap: 8px; } .nav-link { color: var(--text-muted); text-decoration: none; padding: 8px 16px; border-radius: 8px; transition: var(--transition); font-size: 0.9rem; } .nav-link:hover { color: var(--text); background: rgba(255,255,255,0.05); } .nav-link.active { color: var(--accent); background: rgba(56, 189, 248, 0.1); } /* ====== 内容区 ====== */ #route-view { flex: 1; padding: 32px 24px; max-width: 1200px; margin: 0 auto; width: 100%; } .page-container { animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } /* ====== 首页 ====== */ .home-page { text-align: center; padding-top: 80px; } .home-page h1 { font-size: 2.5rem; margin-bottom: 12px; } .subtitle { color: var(--text-muted); font-size: 1.1rem; margin-bottom: 32px; } .btn { padding: 12px 32px; border: none; border-radius: var(--radius); font-size: 1rem; cursor: pointer; transition: var(--transition); } .btn-primary { background: var(--primary); color: white; } .btn-primary:hover { background: var(--primary-hover); transform: translateY(-2px); } .home-stats { display: flex; justify-content: center; gap: 24px; margin-top: 48px; } .stat-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px 32px; display: flex; flex-direction: column; gap: 4px; } .stat-number { font-size: 1.5rem; font-weight: 700; color: var(--accent); } .stat-label { font-size: 0.85rem; color: var(--text-muted); } /* ====== 频道页 ====== */ .channel-header { margin-bottom: 32px; } .channel-header h1 { margin-bottom: 8px; } .channel-header p { color: var(--text-muted); } .module-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; } .module-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; transition: var(--transition); } .module-card:hover { border-color: var(--accent); transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0,0,0,0.3); } .module-icon { font-size: 2rem; } .module-name { font-weight: 600; font-size: 0.95rem; } .module-id { font-size: 0.75rem; color: var(--text-muted); } /* ====== 关于页 ====== */ .about-page h1 { margin-bottom: 16px; } .about-page p { margin-bottom: 12px; color: var(--text-muted); line-height: 1.6; } .about-tech { margin-top: 32px; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; } .about-tech h3 { margin-bottom: 12px; } .about-tech ul { list-style: none; padding: 0; } .about-tech li { padding: 4px 0; color: var(--text-muted); } .about-tech li::before { content: '▸ '; color: var(--accent); } /* ====== 底部状态栏 ====== */ #status-bar { display: flex; justify-content: space-between; align-items: center; padding: 8px 24px; background: var(--bg-nav); border-top: 1px solid var(--border); font-size: 0.8rem; color: var(--text-muted); } /* ====== 响应式 ====== */ @media (max-width: 768px) { .home-page h1 { font-size: 1.8rem; } .home-stats { flex-direction: column; align-items: center; } .module-grid { grid-template-columns: repeat(2, 1fr); } #main-nav { padding: 0 16px; } #route-view { padding: 24px 16px; } } @media (max-width: 480px) { .module-grid { grid-template-columns: 1fr; } .nav-links { gap: 4px; } .nav-link { padding: 6px 10px; font-size: 0.8rem; } } ``` **Step 0-6 · 测试环节0** ```bash open index.html ``` 在浏览器中验证: - [ ] 页面打开显示「欢迎来到光湖」首页 - [ ] 点击「我的频道」→ 内容切换到频道页(模块卡片网格)→ URL变成 `#/channel` - [ ] 点击「关于」→ 内容切换到关于页 → URL变成 `#/about` - [ ] 点击「首页」→ 回到首页 → URL变成 `#/home` - [ ] **全程页面不刷新**,只有内容区在变 - [ ] 导航栏当前页面高亮 - [ ] 页面切换时有淡入动画 - [ ] 底部状态栏显示当前路由路径 --- ### 环节1 · 模块动态加载 **Step 1-1 · 创建模拟模块文件** ```bash mkdir -p mock-modules nano mock-modules/m06-ticket.html ``` 写入: ```html

📋 工单管理 · M06

🟢 前端登录页样式修复 2026-03-08
🟡 数据统计面板响应式适配 2026-03-07
🔴 组件库主题切换闪烁问题 2026-03-06
``` ```bash nano mock-modules/m08-analytics.html ``` 写入: ```html

📊 数据统计 · M08

1,247总访问量
89活跃用户
23今日工单
99.7%系统可用率
``` ```bash nano mock-modules/m11-theme.html ``` 写入: ```html

🎨 风格组件库 · M11

这是你亲手搭建的组件库!CSS变量系统 + 双主题 + 6类组件 + 响应式。

``` **Step 1-2 · 创建模块加载器(module-loader.js)** ```bash nano module-loader.js ``` 写入: ```jsx /** * 光湖模块加载器 · Module Loader v1.0 * 功能:动态加载模块HTML → 渲染到频道页面 */ var ModuleLoader = { // 模块注册表:模块ID → 文件路径 registry: { 'm06': { name: '工单管理', icon: '📋', path: 'mock-modules/m06-ticket.html' }, 'm08': { name: '数据统计', icon: '📊', path: 'mock-modules/m08-analytics.html' }, 'm11': { name: '风格组件库', icon: '🎨', path: 'mock-modules/m11-theme.html' } }, // 缓存已加载的模块(避免重复请求) cache: {}, // 加载模块 load: function(moduleId, container) { var self = this; var module = this.registry[moduleId]; if (!module) { container.innerHTML = '

模块不存在

模块ID: ' + moduleId + '

'; return; } // 检查缓存 if (this.cache[moduleId]) { container.innerHTML = this.cache[moduleId]; console.log('📦 从缓存加载模块: ' + moduleId); return; } // 显示加载状态 container.innerHTML = '

正在加载 ' + module.name + '...

'; // 用fetch动态加载HTML文件 fetch(module.path) .then(function(response) { if (!response.ok) { throw new Error('加载失败: ' + response.status); } return response.text(); }) .then(function(html) { self.cache[moduleId] = html; container.innerHTML = html; console.log('✅ 模块加载成功: ' + moduleId); }) .catch(function(error) { container.innerHTML = '

⚠️ 加载失败

' + error.message + '

'; console.error('❌ 模块加载失败:', error); }); }, // 获取所有已注册模块列表 getAll: function() { return this.registry; } }; ``` **Step 1-3 · 在index.html引入module-loader.js** 用nano打开index.html,在 `` **前面**加一行: ```bash nano index.html ``` 找到这一行: ```html ``` 改成: ```html ``` **Step 1-4 · 升级app.js — 接入模块加载器** ```bash nano app.js ``` 把整个频道路由(`ChannelRouter.register('/channel', ...)`)替换成以下内容。**其他路由不要动**,只改 `/channel` 这一段: ```jsx // 用户频道(已接入模块动态加载) ChannelRouter.register('/channel', function(view) { var modules = ModuleLoader.getAll(); var cardsHtml = ''; for (var id in modules) { var m = modules[id]; cardsHtml += '
'; cardsHtml += '' + m.icon + ''; cardsHtml += '' + m.name + ''; cardsHtml += '' + id.toUpperCase() + ''; cardsHtml += '
'; } // 加一个「更多模块」占位卡片 cardsHtml += '
'; cardsHtml += ''; cardsHtml += '更多模块'; cardsHtml += '陆续上线'; cardsHtml += '
'; view.innerHTML = '
' + '

📺 我的频道

点击模块卡片 → 动态加载模块内容

' + '
' + cardsHtml + '
'; }); ``` 然后在 `ChannelRouter.start();` **前面**加一个模块路由: ```jsx // 模块详情页(动态加载) ChannelRouter.register('/module', function(view) { var route = ChannelRouter.getRoute(); var parts = route.split('/'); var moduleId = parts[2] || ''; if (!moduleId) { ChannelRouter.navigate('/channel'); return; } ModuleLoader.load(moduleId, view); }); ``` ⚠️ **注意**:还需要修改路由器的匹配逻辑,让 `/module/m06` 这种路径能匹配到 `/module` 路由。 **Step 1-5 · 升级路由器支持路径前缀匹配** ```bash nano channel-router.js ``` 找到 `render` 函数里的这一段: ```jsx if (this.routes[route]) { ``` 替换 `render` 函数的匹配逻辑为: ```jsx render: function() { var route = this.getRoute(); var view = document.getElementById('route-view'); var routeDisplay = document.getElementById('current-route'); var handler = null; // 精确匹配 if (this.routes[route]) { handler = this.routes[route]; } else { // 前缀匹配(支持 /module/m06 匹配到 /module) for (var path in this.routes) { if (route.indexOf(path + '/') === 0) { handler = this.routes[path]; break; } } } if (handler) { this.currentRoute = route; handler(view); routeDisplay.textContent = '当前路由:' + route; this.updateNavHighlight(route); } else { view.innerHTML = '

404

页面不存在

回到首页
'; routeDisplay.textContent = '当前路由:404'; } }, ``` **Step 1-6 · 补充模块加载相关CSS** ```bash nano channel-style.css ``` 在文件最底部(`@media` 之前)追加: ```css /* ====== 模块加载状态 ====== */ .loading-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 80px 0; color: var(--text-muted); } .loading-spinner { width: 40px; height: 40px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; margin-bottom: 16px; } @keyframes spin { to { transform: rotate(360deg); } } /* ====== 已加载模块通用样式 ====== */ .loaded-module { animation: fadeIn 0.3s ease; } .module-header { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid var(--border); } .btn-back { background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted); padding: 8px 16px; border-radius: 8px; cursor: pointer; transition: var(--transition); } .btn-back:hover { color: var(--text); border-color: var(--accent); } /* ====== 模拟模块内部样式 ====== */ .ticket-list { display: flex; flex-direction: column; gap: 12px; } .ticket-item { display: flex; align-items: center; gap: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; } .ticket-title { flex: 1; } .ticket-date { color: var(--text-muted); font-size: 0.85rem; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; } .stat-box { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; text-align: center; display: flex; flex-direction: column; gap: 4px; } .stat-val { font-size: 1.5rem; font-weight: 700; color: var(--accent); } .stat-lbl { font-size: 0.8rem; color: var(--text-muted); } .theme-demo { margin-top: 16px; display: flex; gap: 12px; } ``` **Step 1-7 · 测试环节1** ⚠️ **重要**:`fetch()` 在本地文件(`file://`)协议下不工作。你需要用终端启动一个简单的本地服务器: ```bash cd /Users/chenshujun/Desktop/guanghulab/modules/m-channel python3 -m http.server 8080 ``` 然后在浏览器打开 `http://localhost:8080` 验证: - [ ] 首页正常显示 - [ ] 点击「我的频道」→ 显示模块卡片网格(M06/M08/M11 + 更多模块) - [ ] 点击「工单管理」卡片 → 显示加载动画 → 显示工单列表 → URL变成 `#/module/m06` - [ ] 点击「数据统计」卡片 → 显示统计面板 → URL变成 `#/module/m08` - [ ] 点击「风格组件库」卡片 → 显示组件库 → URL变成 `#/module/m11` - [ ] 每个模块页面都有「← 返回频道」按钮,点击能回到频道 - [ ] 第二次打开同一个模块 → 控制台显示「从缓存加载」 - [ ] 模块切换时有淡入动画 --- ## 五、验收标准 | 编号 | 检查项 | 通过标准 | ✅/❌ | | --- | --- | --- | --- | | A-01 | SPA路由工作 | 点击导航链接 → 内容切换 → 页面不刷新 → URL hash变化 | | | A-02 | 三个页面可达 | 首页(#/home) + 频道(#/channel) + 关于(#/about) 均可正常显示 | | | A-03 | 导航高亮 | 当前页面对应的导航链接高亮显示 | | | A-04 | 404处理 | 输入不存在的hash路径 → 显示404页面 | | | A-05 | 模块卡片网格 | 频道页显示M06/M08/M11三个模块卡片 + 更多模块占位 | | | A-06 | 模块动态加载 | 点击模块卡片 → fetch加载HTML → 内容显示在页面上 | | | A-07 | 模块缓存 | 第二次加载同一模块 → 控制台显示「从缓存加载」→ 瞬间显示 | | | A-08 | 返回导航 | 模块详情页有「返回频道」按钮 → 点击回到模块列表 | | | A-09 | 过渡动画 | 页面/模块切换时有淡入动画效果 | | | A-10 | Git推送 | `git add . && git commit && git push` 成功 | | --- ## 六、SYSLOG回执模板 完成后复制以下模板,填写后发给知秋: ```xml BC-M-CHANNEL-001-JZ BC-M-CHANNEL-001-JZ DEV-010 2026-03-XX SPA路由框架 - 完成/未完成 模块动态加载 - 完成/未完成 遇到的问题 有效的解决方式 ``` --- ## 七、PGP · 成长型微调 ---