1. 为什么我要折腾一个纯前端导航页事情的起因特别简单。我平时要查资料、看论文、找一些辅助工具浏览器书签栏早就塞满了换台电脑或者用手机的时候又得重新找一遍。更麻烦的是有些聚合入口页面加载慢、广告多还动不动要登录。我就想能不能自己做一个纯前端的导航页打开就能用不依赖后端不存任何数据换设备只要打开同一个 HTML 文件就行。这个想法落地之后我发现它其实是一个特别适合拿来练手 AI 辅助编程的小项目。整个页面就是一个 HTML 文件里面塞了 CSS 和 JavaScript双击就能在浏览器里跑起来。没有服务器、没有数据库、没有构建工具甚至连 npm 都不用装。你把它丢到任何静态托管上或者直接发给朋友对方打开就能看到你整理好的导航内容。我给它起的定位是“免登录聚合入口”——打开即用不收集任何信息所有链接和分类都写死在页面里想改就改源码。核心关键词就四个Yandex、AI、纯前端、导航页。Yandex 在这里的角色是搜索引擎入口之一我会把它和其他常用搜索、工具站放在一起方便一键跳转。AI 则是整个制作过程的加速器——我用 AI 帮我生成页面骨架、写样式、补交互逻辑自己只做筛选和微调。适合谁来参考如果你有一点 HTML 基础想做一个自己的浏览器起始页或者你完全不懂代码但愿意让 AI 帮你写然后自己复制粘贴再或者你是个前端新手想找一个真实的小项目练手这个导航页都挺合适。它不涉及任何后端逻辑所以不用担心安全问题也不用备案、不用买服务器。下面我就把整个思路、实现细节、踩过的坑以及怎么用 AI 快速生成完整地拆一遍。2. 整体设计与技术选型思路2.1 为什么坚持纯前端纯前端的意思是这个页面所有的逻辑都在浏览器里跑不需要向服务器请求数据。导航页这种场景天然适合纯前端因为它的核心功能就是“展示链接”和“跳转”没有任何需要服务端参与的地方。用户打开页面浏览器解析 HTML、渲染样式、执行一点 JavaScript 做搜索过滤或者主题切换完事。我试过用后端渲染的方案比如用 Node.js 起一个服务每次请求动态生成页面。结果就是部署麻烦、维护成本高而且一旦服务挂了页面就打不开。纯前端方案把这些问题全干掉了一个 HTML 文件复制到哪都能跑断网也能打开只要文件在本地加载速度就是浏览器解析一个文件的速度。还有一个很实际的原因纯前端不需要登录。没有后端就没有用户系统也就没有“登录才能用”这种破事。你打开就是全部功能关掉不留痕迹。对于导航页这种工具属性极强的页面这是最舒服的体验。2.2 单文件结构 vs 多文件拆分我一开始想的是把 HTML、CSS、JavaScript 拆成三个文件看起来更“规范”。但实际用下来单文件反而更合适。原因有三个第一分发方便一个文件发给别人就行不用打包压缩第二没有路径问题不会出现 CSS 加载失败导致页面裸奔第三修改的时候不用在多个文件之间跳来跳去。当然单文件也有缺点就是文件会比较大几千行堆在一起。但导航页的代码量其实很有限我最后做出来大概 800 行左右其中大部分是链接数据和样式。用编辑器折叠一下维护起来完全没问题。如果你实在觉得长可以用注释把区域划分清楚比如“搜索区”“分类区”“样式区”“脚本区”。2.3 数据写死还是动态加载导航页的链接数据有两种存法一种是直接写在 HTML 里另一种是放在 JavaScript 数组里动态渲染。我选了后者。原因是动态渲染更方便做搜索过滤和分类折叠。如果链接直接写在 HTML 里想加一个搜索框过滤就得用 DOM 操作去遍历节点代码又臭又长。放在数组里过滤就是对一个数组做 filter然后重新渲染逻辑清晰得多。数据结构也很简单就是一个对象数组每个对象包含名称、链接、分类、描述这几个字段。分类用来分组描述用来在鼠标悬停时显示提示。这个结构用 AI 生成特别快你只要告诉它“给我生成一个包含 50 个常用工具链接的 JSON 数组字段有 name、url、category、desc”它几秒钟就吐出来了。2.4 搜索功能的设计取舍搜索框我做了两个用途一是过滤当前页面的链接二是直接跳转到 Yandex 搜索。怎么区分我的做法是输入内容后按回车如果输入的是网址包含点号或者 http就直接跳转否则就调用 Yandex 的搜索接口把关键词拼到 URL 里跳过去。这样用户不用先选搜索引擎再输入一个框搞定两件事。这里有个细节Yandex 的搜索 URL 格式是https://yandex.com/search/?text关键词。关键词需要用encodeURIComponent编码不然中文和特殊字符会出问题。这个编码步骤很多人会忘导致搜索中文时链接断裂。我在代码里专门处理了这一步后面会贴出来。2.5 主题切换的必要性导航页是每天都要打开的东西白天和晚上光线不一样固定一个配色肯定不舒服。我加了明暗两套主题默认跟随系统也可以手动切换。实现方式是用 CSS 变量定义颜色切换的时候只改变量值不用重写样式。这个方案的好处是切换瞬间完成没有闪烁而且新增颜色只要改变量定义就行。主题切换的状态存在localStorage里下次打开还记得你的选择。这里注意一点localStorage是纯前端存储不会上传到任何地方清除浏览器数据就会重置。如果你不想留任何痕迹可以把这段逻辑去掉默认就用系统主题。3. 核心细节解析与实操要点3.1 页面骨架怎么搭整个页面分三个区域顶部搜索区、中间分类导航区、底部信息区。顶部放搜索框和主题切换按钮中间按分类展示链接卡片底部放一句说明和当前时间。布局用 Flexbox 和 Grid 混合顶部用 Flex 做水平排列中间用 Grid 做自适应卡片布局。Grid 的列数我用的是repeat(auto-fill, minmax(200px, 1fr))意思是每列最小 200px能塞几列塞几列剩余空间平均分配。这样在宽屏上显示四五列在手机上自动变成一列不用写媒体查询。这个技巧我强烈推荐比手动断点简单多了。卡片内部用 Flex 做垂直排列名称在上描述在下。描述文字用text-overflow: ellipsis做截断防止长描述撑破卡片。悬停时卡片轻微上浮并加阴影给一个视觉反馈。这些样式都不复杂但组合起来体验就很顺。3.2 链接数据的组织方式数据我放在一个叫links的数组里每个元素长这样{ name: Yandex, url: https://yandex.com, category: 搜索引擎, desc: 俄罗斯最大的搜索引擎支持多语言搜索 }分类我一开始分了七八个后来精简到五个搜索引擎、AI 工具、开发资源、效率工具、学习资料。分类太多反而找不到东西五个刚好每个分类下面十到二十个链接一屏能看完。这里有个经验链接的desc字段不要写太长控制在 20 个字以内。太长了卡片显示不全鼠标悬停看提示又麻烦。我一般写一句最核心的说明比如“支持多语言的搜索引擎”就够了。3.3 搜索过滤的实现细节搜索框的input事件触发过滤函数函数里做三件事拿到输入值、转小写、遍历links数组匹配name和desc字段。匹配用includes就行不需要正则简单可靠。匹配到的链接重新渲染到页面上没匹配到的隐藏。这里有个性能小技巧不要每次输入都重新创建 DOM 节点而是先创建好所有卡片过滤的时候只切换display属性。这样输入的时候不会有卡顿尤其是链接多的时候。我试过重新渲染的方案输入快的时候会掉帧改成切换显示之后就流畅了。回车跳转的逻辑单独处理判断输入值是否包含.或者http如果是就当网址处理直接window.location.href 输入值否则拼 Yandex 搜索链接。拼链接的时候记得编码const query encodeURIComponent(inputValue); window.location.href https://yandex.com/search/?text${query};3.4 主题切换的变量方案CSS 变量定义在:root里明暗两套用[data-themedark]覆盖:root { --bg: #ffffff; --text: #1a1a1a; --card-bg: #f5f5f5; } [data-themedark] { --bg: #1a1a1a; --text: #e0e0e0; --card-bg: #2a2a2a; }切换的时候改document.documentElement.dataset.theme的值CSS 自动生效。存localStorage的键叫theme值就是light或dark。页面加载时先读localStorage没有就跟随系统const saved localStorage.getItem(theme); const prefersDark window.matchMedia((prefers-color-scheme: dark)).matches; const theme saved || (prefersDark ? dark : light); document.documentElement.dataset.theme theme;这段代码放在head里避免页面加载时闪白。我一开始放在/body前面结果暗色主题下打开会先闪一下白屏体验很差。移到head里就解决了。3.5 用 AI 生成代码的提示词技巧我用 AI 生成这个页面的时候提示词是分步给的不是一次性让它写完整页面。第一步让它生成 HTML 骨架和 CSS 样式第二步让它生成链接数据第三步让它补搜索和主题切换的 JavaScript。分步的好处是每一步都能检查错了容易改不会一坨代码丢过来不知道从哪下手。提示词里我会明确说“纯前端”“单文件”“不用任何框架”“不用外部 CDN”。这几个约束很重要不然 AI 默认会给你引入 Bootstrap 或者 Tailwind虽然好看但增加了依赖违背了纯前端的初衷。如果你想要样式好看又不想引入框架可以让 AI 用原生 CSS 写它现在写得挺好的。还有一个技巧让 AI 生成代码的时候要求它加注释。比如“每一段 JavaScript 都加中文注释说明用途”。这样你拿到代码之后能看懂改起来也方便。我试过不加注释的版本过两天自己都忘了哪段是干嘛的。4. 完整实操流程与关键环节4.1 从零开始搭建的步骤第一步新建一个文件叫index.html用编辑器打开。第二步把下面这段骨架复制进去!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的导航页/title style /* 样式写这里 */ /style /head body header input typetext idsearch placeholder搜索或输入网址... button idtheme-toggle切换主题/button /header main idnav/main footer p纯前端导航页 · 数据仅存本地/p /footer script /* 脚本写这里 */ /script /body /html第三步把 CSS 变量和基础样式补上。第四步定义links数组。第五步写渲染函数和搜索逻辑。第六步写主题切换。第七步在浏览器里打开测试。整个过程如果手动写大概需要两三个小时。用 AI 辅助的话半小时就能跑起来。我的做法是让 AI 生成初版然后自己调样式和补充链接。AI 生成的代码不一定完全符合你的审美但骨架和逻辑是对的改起来比从零写快得多。4.2 链接数据的批量生成手动一个个填链接太慢了。我的做法是让 AI 生成一批然后自己筛选。提示词可以这样写“生成一个 JavaScript 数组包含 30 个常用 AI 工具网站每个元素有 name、url、category、desc 四个字段category 统一为‘AI 工具’desc 用一句中文说明用途。”AI 会给你一个完整的数组你复制到代码里就行。但要注意AI 生成的 URL 可能不准确尤其是比较新的网站。我一般会抽查几个确认能打开。另外 AI 可能会编造一些不存在的网站所以生成之后要自己过一遍把打不开的删掉。筛选的标准很简单你平时真的会用。导航页不是链接收藏夹不需要什么都放。我最后只留了 50 个左右的链接每个都是高频使用的。链接太多反而找不到少而精才是导航页的价值。4.3 搜索框的交互打磨搜索框的交互有几个细节值得打磨。第一自动聚焦页面加载后光标直接落在搜索框里打开就能打字。第二输入时实时过滤不用按回车。第三按回车时判断是搜索还是跳转。第四按 Esc 清空输入并恢复全部链接。自动聚焦用autofocus属性就行但注意在移动端可能会自动弹出键盘影响体验。我的做法是只在桌面端自动聚焦移动端不聚焦。判断方式是用window.innerWidth或者matchMedia检测屏幕宽度。实时过滤的防抖处理如果链接很多每次输入都过滤可能会卡。加一个 100 毫秒的防抖输入停止后再过滤。不过我的链接只有 50 个实测不防抖也不卡所以就没加。如果你的链接超过 200 个建议加上防抖。4.4 响应式布局的适配响应式主要靠 Grid 的auto-fill和minmax实现前面说过了。但有几个地方需要额外处理搜索框在窄屏上要占满宽度主题切换按钮要缩小卡片的内边距在手机上要减小底部文字要居中。我用的断点只有一个max-width: 600px。小于 600px 的时候搜索框宽度 100%按钮只显示图标不显示文字卡片内边距从 16px 减到 12px。这些调整用媒体查询写几行代码就够了。还有一个细节viewport的meta标签一定要写不然手机上会按桌面宽度渲染字小得看不清。这个标签我见过很多人忘写导致移动端体验极差。4.5 部署与分发方式纯前端页面的部署特别简单。方式一直接把 HTML 文件发给别人对方双击打开。方式二丢到任何静态托管服务上比如 GitHub Pages、Netlify、Vercel拖拽上传就行不需要配置。方式三放在自己的服务器上用 Nginx 指向文件目录。我常用的是方式二因为可以生成一个链接手机和电脑都能访问。部署的时候注意一点如果你的页面引用了外部资源比如字体、图标要确保这些资源也能访问不然页面会缺样式。我的做法是不引用任何外部资源图标用 Unicode 字符或者内联 SVG字体用系统默认这样部署到哪都不会出问题。5. 常见问题与排查技巧实录5.1 页面打开空白怎么办最常见的原因是 JavaScript 报错导致渲染中断。排查方法按 F12 打开开发者工具看 Console 面板有没有红色报错。如果有根据报错信息定位到具体行。常见错误包括数组拼写错误、函数名写错、括号不匹配。另一个原因是links数组为空或者格式不对。检查数组里每个元素是否有name和url字段缺了会导致渲染函数报错。我建议在渲染函数开头加一个判断如果数组为空显示一句“暂无链接”而不是直接报错。还有一种情况是文件编码问题。如果 HTML 文件保存成了 GBK 编码而meta标签写的是 UTF-8中文会乱码。解决办法是用编辑器把文件另存为 UTF-8 编码。VS Code 右下角可以看和改编码。5.2 搜索跳转链接不对这个问题通常是编码没做。中文关键词直接拼到 URL 里浏览器可能会截断或者乱码。一定要用encodeURIComponent处理。另外 Yandex 的搜索域名是yandex.com如果你用的是其他区域域名要相应替换。还有一个坑如果用户输入的内容本身就是一个完整 URL比如https://example.com你再用encodeURIComponent编码后拼到搜索链接里就会变成搜索这个 URL 而不是跳转。所以要先判断是不是 URL是的话直接跳转不是才搜索。判断逻辑可以这样写function isUrl(str) { return /^(https?:\/\/)?([\w-]\.)[\w-]/.test(str); }这个正则不完美但够用。匹配到就跳转匹配不到就搜索。5.3 主题切换后刷新失效原因是没存localStorage或者存了但读取的时机不对。存的时候用localStorage.setItem(theme, theme)读的时候在head里同步读取。如果读取放在DOMContentLoaded事件里页面会先渲染默认主题再切换造成闪烁。正确的做法是在head里写一段内联脚本同步执行script (function() { const saved localStorage.getItem(theme); const prefersDark window.matchMedia((prefers-color-scheme: dark)).matches; document.documentElement.dataset.theme saved || (prefersDark ? dark : light); })(); /script这段脚本要在 CSS 之前执行这样样式应用的时候主题已经确定了。5.4 移动端点击链接没反应这个问题通常是因为卡片上的点击事件被其他元素挡住了。检查一下卡片的z-index和position属性确保链接的a标签覆盖整个卡片区域。我的做法是把a标签设为display: block宽高 100%这样点击卡片任何位置都能跳转。另一个原因是touch事件和click事件的冲突。如果你在卡片上绑定了touchstart又绑定了click可能会触发两次。纯前端导航页一般不需要touch事件用click就够了浏览器会自动处理触摸。5.5 常见问题速查表问题现象可能原因排查方法解决方案页面空白JS 报错F12 看 Console根据报错修代码中文乱码文件编码不对看编辑器编码另存为 UTF-8搜索乱码未编码检查 URL用 encodeURIComponent主题闪烁读取时机晚看 head 脚本移到 head 同步执行移动端点不动元素遮挡检查 z-index调整层级和点击区域链接打不开URL 错误手动访问测试修正或删除链接布局错乱Grid 不兼容看浏览器版本加 fallback 样式5.6 我踩过的几个坑第一个坑一开始我把links数组写在了/body前面的script里结果渲染函数执行的时候数组还没定义报错links is not defined。解决办法是把数组定义放在渲染函数调用之前或者把渲染调用放在DOMContentLoaded事件里。第二个坑主题切换按钮的点击事件绑在了button上但按钮里面有个span放图标点击span的时候事件没触发。解决办法是用事件委托绑在button上然后判断event.target是不是按钮本身或者它的子元素。第三个坑搜索过滤的时候我用innerHTML重新渲染整个列表导致输入框失去焦点。因为innerHTML会替换整个main的内容如果搜索框在main里面就会被替换掉。解决办法是把搜索框放在main外面或者只更新卡片的display属性不重新渲染。第四个坑Yandex 的搜索链接在有些地区访问慢我一开始以为是代码问题后来发现是网络原因。这个没办法只能接受。如果你主要用其他搜索引擎可以把默认搜索换成别的代码逻辑一样改个 URL 就行。6. 用 AI 加速开发的实际体验6.1 AI 在哪些环节最省时间对我来说AI 最省时间的环节是写 CSS 样式和生成链接数据。CSS 样式虽然不难但写起来琐碎尤其是响应式调整和悬停效果让 AI 生成初版然后自己微调比从零写快很多。链接数据更是如此手动收集 50 个网站的信息至少要半小时AI 几秒钟就生成好了我只需要筛选和验证。JavaScript 逻辑 AI 也能写但需要你描述清楚需求。比如“写一个函数接收输入字符串如果包含点号就跳转否则拼 Yandex 搜索链接”这种描述越具体AI 生成的代码越准确。如果你只说“写个搜索功能”它可能会给你一个很复杂的实现反而不好用。6.2 AI 生成代码的常见问题AI 生成的代码有几个通病。第一喜欢引入外部库比如用 jQuery 做 DOM 操作用 Moment.js 做时间格式化。这些库虽然方便但增加了依赖违背纯前端单文件的初衷。解决办法是在提示词里明确说“不用任何外部库”。第二代码风格不统一有时候用var有时候用const有时候用箭头函数有时候用function。这个不影响运行但看起来乱。我的做法是生成之后自己统一一遍或者让 AI 按指定风格重写。第三注释可能是英文的或者干脆没注释。如果你需要中文注释要在提示词里说清楚。我一般会要求“每段代码加中文注释说明用途和注意事项”。6.3 怎么让 AI 理解你的需求让 AI 理解需求的关键是提供足够的上下文。不要只说“帮我写个导航页”而要说“帮我写一个纯前端的导航页单 HTML 文件包含搜索框、分类链接卡片、明暗主题切换不用任何外部库样式用原生 CSS数据存在 JavaScript 数组里”。另外分步提需求比一次性提完整需求效果好。先让 AI 生成骨架再让它补样式再让它加交互。每一步都检查一下有问题及时纠正。如果一次性让它写完整页面代码量太大出了问题不好定位。还有一个技巧给 AI 看你想要的参考样式。比如你看到一个导航页觉得不错可以把它的截图或者 HTML 结构描述给 AI让它照着写。这样生成的代码更接近你的预期。6.4 AI 辅助开发的边界AI 能帮你写代码但不能帮你做决策。比如分类怎么分、链接放哪些、配色用什么这些需要你自己判断。AI 生成的方案是一个起点不是终点。我见过有人直接把 AI 生成的页面拿来用结果链接一半打不开分类乱七八糟体验很差。另外AI 生成的代码可能有安全漏洞虽然纯前端导航页的风险很低但如果你要处理用户输入比如搜索框还是要注意 XSS 攻击。我的做法是对用户输入不做任何 HTML 渲染只用textContent设置文本避免注入。最后AI 不能替代测试。生成的代码一定要在浏览器里实际跑一遍点一点、搜一搜、切换主题看看确认没问题再发布。我每次改完代码都会刷新页面测试这个习惯帮我省了很多麻烦。7. 后续可以怎么扩展这个导航页的骨架已经能用了但如果你想继续折腾有几个方向可以扩展。第一个是加一个“常用”分类把最常用的几个链接置顶不用每次搜索。实现方式是在数据里加一个pinned字段渲染的时候优先显示。第二个是加键盘快捷键比如按/聚焦搜索框按1到5切换分类。这个用keydown事件监听就行代码量不大但用起来很顺手。第三个是加导入导出功能把链接数据存成 JSON 文件换设备的时候导入。这个需要用到Blob和FileReader稍微复杂一点但也不难。导出就是把数组转成 JSON 字符串下载导入就是读取文件解析成数组。第四个是加一个简单的访问统计用localStorage记录每个链接的点击次数按次数排序。这个纯前端就能做不需要后端。不过要注意localStorage有容量限制别存太多数据。我个人的体会是导航页这种东西不需要一次做完美先用起来用着用着就知道哪里需要改。我第一版只有 20 个链接和一个搜索框后来慢慢加到 50 个链接、加了主题切换、加了分类过滤。每次改动都很小但积累起来体验就上来了。如果你也想做一个建议先从最简单的版本开始跑起来之后再迭代。