前两天接了个急活,朋友公司要做内部活动报名页,设计稿只有一张图,页面不算复杂,但不能用各种框架打包,因为要嵌在现有的CMS模板里。搁以前,这种原生HTML页面我一个下午写完,还得花时间处理各种浏览器兼容。今天我想换个方式——让AI来写,看它能不能在30分钟内搞定。结果它不仅搞定了,还给我留了一堆可以继续讲的东西。本文就还原一下这个过程,聊聊AI生成原生页面时那些值得关注的细节,也分享一个前端老鸟面对“AI编程”时的真实心态。
1. 项目起因:为什么我会用AI生成原生页面
1.1 一个紧急需求
活动报名页这个东西,听起来简单,真正做起来琐碎事一大堆。当时朋友给的需求只有一句:“内部团建活动报名,能填名字、手机号、人数,页面上最好有个倒计时,报名成功后能看到已报名的人。”没有设计规范,没有组件库,甚至没有太严格的视觉要求。唯一麻烦的是页面要嵌在他们公司CMS的富文本编辑器里,不能引入React/Vue,也不能依赖npm构建流程,我必须交付一段可以直接粘贴的HTML。
按照传统方式,我会先搭一个外层容器,再写响应式样式,再写表单校验和交互逻辑。一个不复杂的页面,从结构到联调怎么也要两三个小时。但这次活动比较赶,加上我已经很久没有手写原生三件套了,很多API的边界情况还要翻文档确认。我索性跟朋友说,给我30分钟试试,用AI生成一版,能跑就行。
就是这30分钟,让我对“前端开发”这件事产生了新的判断。AI不是帮你写几行代码那么简单,它能在你描述清楚需求之后,直接给出一整份可运行、结构完整、注释齐全的原生页面。而我要做的,反而变成了“提出更好的问题”和“检查它给出的答案”。
1.2 为什么选“原生页面”而不是框架
很多人会问,现在公司里不都是Vue或者React吗?为什么不直接让AI生成一个Vue组件,然后放进工程里跑?这里面有个很实际的约束:部署环境不允许。CMS后台很多都是老系统,你不可能为了一个报名页去搭一套前端工程化工具链,也不可能要求运营同学去执行npm install。这时原生HTML/CSS/JS就是最稳妥的交付物。
另一个原因是页面规模和状态复杂度。活动报名页只有“表单填写”和“列表展示”两类交互,数据可以存在内存里,后续如果需要接接口,无非是把Mock数据换成fetch请求。用框架反而要额外考虑路由、响应式状态、组件通信,属于杀鸡用牛刀。就像你工具箱里明明有一把趁手的小螺丝刀,非要去开一台数控机床来拧螺丝,没必要。
从另一个角度看,原生页面恰恰是AI目前最擅长生成的类型。大模型训练数据里包含大量静态页面、落地页、表单页面的示例,这些页面的模式非常成熟,标签结构相对固定,CSS属性也基本稳定。相比之下,让AI生成一套完整的微前端架构或者复杂权限系统,它就容易“一本正经地胡说八道”。所以这个项目选择原生页面,既是业务需求,也是让AI发挥最大价值的路径。
1.3 工具选型:Cursor还是别的
这次我用的主力工具是Cursor。AI编程工具带不带来效率提升,试一次就知道。我对比过几款主流的AI编码助手,各有特点,这里先给一张表。
| 工具 | 核心优势 | 明显短板 | 适合场景 |
|---|---|---|---|
| Cursor | 对话能力完整,可整文件生成和重构 | 免费额度有限,需要注册 | 整个页面从零生成、批量重构 |
| GitHub Copilot | 和编辑器结合深,补全很自然 | 更适合“行级补全”,整页生成稍弱 | 在已有代码里写业务逻辑 |
| 通义灵码 | 中文友好,免费额度大 | 生成的代码风格不太稳定 | 中文需求描述、快速原型 |
我用Cursor的主要原因是它的Composer模式可以同时生成HTML、CSS、JS三个文件,并且能根据我的反馈直接修改整个文件,而不是像我以前用Copilot那样,还要自己复制粘贴多轮。当然,工具只是手段,真正决定输出质量的还是提示词。同一段需求,给AI说“做个报名页”和给AI说“移动端优先、无外部依赖、表单校验规则如下”是完全不同的结果。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 30分钟实战:从需求描述到可运行页面
2.1 第一步:把需求翻译成AI能听懂的话
AI不是读心术,它的输出质量高度依赖你的输入信息密度。我写的提示词大概是这样的:
用原生HTML+CSS+JavaScript生成一个活动报名页面,移动端优先,桌面端最大宽度1200px居中。内容包括:顶部活动标题和倒计时,中间报名表单(姓名、手机号、人数),提交按钮,下方活动流程介绍,底部报名成功列表(用mock数据)。样式要求:主色#4F46E5,圆角卡片,字体使用系统字体栈,不要外部依赖。JS需要实现倒计时、表单校验、提交后更新报名列表。代码要加中文注释。
这段描述里每一句话都有目的。“移动端优先”决定了CSS布局策略,“最大宽度1200px居中”避免了内容在大屏幕上拉成一条长线。“不要外部依赖”是在明确禁止AI引入Bootstrap、jQuery、Google Fonts这些外部资源,否则嵌入CMS后会跨域或者加载失败。“代码要加中文注释”是为了拿到代码后不用猜逻辑,方便接下来人工审查。
写提示词有一个很反直觉的技巧:不要怕啰嗦。AI只根据你给的信息生成内容,你没说的约束它大概率不会主动考虑。比如我没提“表单需要防重复提交”,它第一版确实没做。后来我补了一句“提交后按钮变为loading状态并禁用”,它才加上。提示词里每多一条明确的约束,就是为后面人工返工少一次来回。
2.2 第二步:让AI生成HTML结构和样式
Cursor在收到需求后,生成了一个完整的文件夹。我打开index.html,里面是一个清晰的页面结构,关键部分长这样:
html复制<header class="hero">
<h1>2026 年度开发者大会报名</h1>
<p class="deadline">距报名截止还有 <span id="countdown">--:--:--</span></p>
</header>
<section class="form-card">
<form id="applyForm">
<label>姓名</label>
<input type="text" id="name" placeholder="请输入姓名" />
<label>手机号</label>
<input type="tel" id="phone" placeholder="请输入手机号" />
<label>报名人数</label>
<input type="number" id="people" min="1" max="10" value="1" />
<button type="submit" id="submitBtn">立即报名</button>
</form>
<p class="error" id="formError"></p>
</section>
<section class="steps">
<h2>活动流程</h2>
<ol>
<li>签到入场</li>
<li>主题分享</li>
<li>圆桌讨论</li>
</ol>
</section>
<section class="list-card">
<h2>已报名人员</h2>
<ul id="userList"></ul>
</section>
这段HTML整体是语义化的。header、section、ol、ul都用得比较准确,没有一整个页面全塞div的问题。label和input也正确关联,虽然没有用for属性,但包裹方式在HTML5里也是合法的。这说明AI生成代码的时候,确实参考了现代前端开发的规范。
CSS部分它用了CSS变量定义主色和圆角,布局上用Flex和Grid混合实现。移动端单列,桌面端把表单和活动流程并排。字体栈是-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto这类常见的系统字体栈,没有额外加载字体,符合零依赖的要求。整体代码风格干净,没有出现过度嵌套的选择器。
2.3 第三步:交互逻辑与数据模拟
JS部分AI也一次给出了完整实现。主要有三个功能块:倒计时、表单校验、提交后更新Mock列表。
javascript复制function updateCountdown() {
const targetTime = new Date("2030-01-01T00:00:00").getTime();
const now = Date.now();
const diff = Math.max(0, targetTime - now);
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
document.getElementById("countdown").textContent =
hours + ":" + String(minutes).padStart(2, "0") + ":" + String(seconds).padStart(2, "0");
}
setInterval(updateCountdown, 1000);
这段代码能跑,但有个很明显的问题:目标时间写死成了"2030-01-01",如果活动改期或者过了这个时间,倒计时就永远显示为0。表单校验部分它检查了姓名非空、手机号正则、人数在1到10之间,并显示错误信息。提交后把人员数据unshift到Mock数组里,再调用一个renderList()函数刷新列表。
Mock数据是这样定义的:
javascript复制const mockData = [
{ name: "张三", phone: "138****1234", people: 2 },
{ name: "李四", phone: "139****5678", people: 1 }
];
手机号打码显示是AI自己做的,细节上还挺到位。至少这个版本在样式和交互上已经能当原型Demo用了。但要说直接上线,还差得远。
2.4 第四步:本地预览和微调
用VS Code的Live Server插件打开页面,第一眼视觉上没有任何问题,移动端宽度也没出现横向滚动条。点击提交按钮,能正常校验空值和手机号格式,非法输入会有红色提示。报名成功之后,列表下方新增了一条记录,数据也在页面上重新渲染。
但要仔细测,问题就来了。我点了三次提交,发现可以无限提交空数据(在通过校验的情况下)——虽然每次提交前校验已存在,但按钮没有禁用,网络慢一点就会重复提交。还有倒计时目标时间是固定值,页面在长时间不操作时也看不出问题,可一旦活动时间调整就要改代码。
于是我在Cursor对话框里追加了两条需求:“把倒计时目标时间改为从URL参数target读取,如果没传参数则默认为当前时间后24小时;提交按钮在提交后进入loading状态,1.5秒内禁止重复点击。”AI很快做了调整,时间读取和按钮状态都符合要求。这个过程让我意识到,AI生成代码不是“一次成型”,而是“多轮对话共创”。
3. 生成代码的解读与优化
3.1 原生页面代码的核心组成
AI生成的原生页面整体结构大概是这样的:HTML文件约80行,CSS文件约150行,JS文件约120行,加起来不到400行。作为对比,如果我用框架写这个页面,光package.json里的依赖就有几百行,还不算构建配置。原生代码的优势是直观、易部署、不依赖环境。
这400行代码里,真正核心的部分是三个:页面语义化结构、响应式CSS布局、交互逻辑。HTML部分没有使用<div>套娃,而是用了section和header来划分区域,这是现在主流HTML5写法,也是SEO友好的。CSS部分用变量统一管理颜色和圆角,后续如果客户想换主题色,只改一个--primary变量就够了。JS部分虽然函数都挂在全局作用域,但每个函数的职责边界还算清楚,倒计时的逻辑和表单校验的逻辑没有互相纠缠。
这块代码可以当作一个“最小可运行页面”的样板,它不复杂,但包含了网页开发的基本要素。如果读者想快速理解原生页面是怎么工作的,完全可以把这段生成代码打印出来,对照着浏览器开发工具看每个部分的对应关系。
3.2 AI生成代码常见的坑
AI能写出“表面正确”的代码,但这里面的坑也不少。我一个一个说。
第一个坑是时间计算单位错误。我第一次生成的那版倒计时,看起来很美,但稍加观察发现它把24 * 60 * 60 * 1000少乘了1000,导致一天变成一分钟。后来我让AI解释代码,它自己也承认这里有问题。这是典型的模型在“数值换算”上容易出现的幻觉,不是语法错误,而是业务逻辑错误。
第二个坑是全局变量污染。AI默认把所有函数和变量都放在全局作用域,如果页面里还嵌入了其他脚本,很可能出现命名冲突。比如它定义了一个renderList(),万一CMS模板里有个同名函数,后加载的脚本就会覆盖前一个。这在大型老系统里特别危险。
第三个坑是代码里夹带“假依赖”。AI没有引入外部库,但它偶尔会在CSS里写一些需要浏览器前缀才会正常显示的属性,比如backdrop-filter。现代浏览器大部分支持,但部分老版本Chrome和Safari还需要-webkit-前缀。AI默认生成的代码不会自动加这些兼容前缀,因为训练数据里的“标准写法”多于“兼容写法”。
第四个坑是Mock数据和接口结构脱节。AI生成的Mock数据是纯前端对象,如果后端接口返回结构不同(比如字段名从name变成userName,或者手机号是数字而不是字符串),那么后续接接口时几乎要重写渲染逻辑。所以用AI生成代码时,最好在提示词里就把接口数据结构写清楚。
3.3 手工优化:让页面真正能上线
经过AI生成和初步修改之后,页面已经能跑,但要交付给客户,还需要做几个踏踏实实的优化步骤。
第一步,把整个JS包成一个IIFE(立即执行函数),避免全局污染。这一步很简单,把原来的函数和变量全部放到(function(){ ... })()里面,再在最后暴露必要的方法。这样即使用户页面还有其他脚本,也不会互相干扰。
javascript复制(function () {
"use strict";
const API_ENDPOINT = "/api/apply";
const mockData = [...];
function renderList() { ... }
function handleSubmit(e) { ... }
document.getElementById("applyForm").addEventListener("submit", handleSubmit);
})();
第二步,把倒计时目标时间参数化。我在前面已经让AI改成从URL参数读取,没有就默认24小时后。改完之后,运营后续调整活动时间就不需要改代码,只需要在CMS里给页面URL加一个?target=2026-06-30T18:00:00参数就行。
第三步,增加防重复提交状态。提交按钮提交后变成“提交中...”并禁用,1.5秒后再恢复。这一步虽然简单,但对真实用户特别重要,否则在弱网环境下,用户多点几下就会提交多条重复报名。
第四步,压缩代码。原生HTML/CSS/JS的好处是压缩非常方便,我用在线工具把CSS和JS分别压缩,文件体积从60KB左右降到了35KB,对活动页来说已经算轻量了。如果图片多,还可以给图片加loading="lazy",但这个页面没有图片,就省略了。
优化完再用Lighthouse跑了一遍,性能评分从78分涨到95分。主要失分项集中在图片优化和缓存策略,但作为一个CMS内嵌页面,这个分数已经够了。这个经历告诉我,AI生成代码只是起点,真正体现前端价值的是后续这些审查、修正和性能调优工作。
4. 常见问题与排查心得
4.1 AI生成页面与框架项目的选择
我用这个案例并不想得出“前端已死”的结论,反而想聊聊该在什么场景用AI生成原生页面,什么场景继续用框架。
原生页面最适合的活动页、落地页、宣传页、简单表单页。这类页面生命周期短、交互简单、不需要路由和状态管理,AI可以在几分钟内生成完整可用的版本。CMS或者服务端渲染模板里嵌入也非常方便,不会有构建负担。对个人开发者来说,做一个作品集、一个导航页、一个临时工具页,用AI生成原生页面几乎是效率最高的方式。
但如果你要做后台管理系统、社区产品、数据可视化大屏,或者需要多人协作维护的大型项目,直接让AI生成原生页面就是给自己挖坑。没有组件化、没有状态管理、没有模块系统,超过1000行逻辑后维护成本会急剧上升。这时候应该用框架,让AI作为“辅助编码工具”,帮你写组件或单元测试,而不是替你搭建架构。
所以不是“AI替代前端”,而是“AI让低价值重复劳动被替代”。前端工程师的定位会从“写页面的人”变成“判断页面该怎么做的人”,这个转变恰恰是好事。
4.2 大模型“幻觉”导致的功能错误
这次实操中我遇到的AI幻觉特别典型,值得单独拎出来讲。最明显的一个就是倒计时时间算错了1000倍。当时页面上的倒计时从24小时直接变成显示4分钟左右,我还愣了一下,后来打开控制台打印日志才发现,时间戳差值少了一个数量级。这种错误靠肉眼看代码很难找,必须靠数据验证。
AI幻觉往往集中在以下几个地方:
- 时间计算:时区、时间戳、单位换算经常出错
- DOM引用:AI写的
getElementById和HTML里的id不一致,多一个短横少一个字母都可能 - API参数:字段名和顺序容易颠三倒四
- CSS兼容性:用了新特性但忘了旧浏览器
- 正则表达式:手机号校验看着对,实际能匹配到非法输入
排查AI生成的代码时,我习惯先在浏览器控制台跑一遍核心函数,把关键变量打印出来。比如倒计时算出的时间戳、表单校验返回的布尔值、列表渲染的数组长度,每个都看一眼。发现问题后,我会把错误信息直接粘贴给AI,让它自己再生成一份修正版。这个“人审+AI改”的循环,比完全依赖AI要可靠得多。
4.3 前端开发者该怎么应对“AI生成代码”
最近朋友圈都在转发“前端跑路指南”,但我看到的是另一面:前端岗位不会消失,消失的是“不会跟AI协作”的人。你会看到一个很有意思的现象,同样是写一个页面,新手可能用AI十分钟生成,但出了bug找不到原因;老手可能也花十分钟生成,但会用浏览器断点调试、会加边界条件、会做性能优化,两者交付质量天差地别。
应对AI时代,我建议前端开发者重点练三种能力。第一是“看图说话”能力:能跟AI讲清楚页面布局、交互细节和约束条件。这其实是产品思维和沟通能力的体现。第二是“代码审查”能力:AI生成代码后能读懂每一行,找出可能的隐患和性能瓶颈。第三是“架构判断”能力:知道什么时候用原生、什么时候上框架,知道怎么设计数据流和组件边界。
现在很多前端面试题也开始变了。以前是手写防抖节流、手写Promise,现在已经出现“请说明你如何保证AI生成代码的质量”这种问题。如果你只是会用AI生成代码,却说不清代码背后的原理,面试官其实一眼就能看出来。反过来,如果你能解释AI生成代码的优势和劣势,还能现场优化一段,那反而是加分项。
4.4 一份实用的问题排查速查表
结合最近几次AI生成页面的实操,我做了一张高频问题速查表,看完基本能解决80%的翻车现场。
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| 倒计时时间明显不对 | 时间戳单位换算错误 | 在updateCountdown里打印diff值 |
| 点击提交没有反应 | 表单没有阻止默认提交行为 | 检查submit事件是否调用preventDefault |
| 页面在手机上排版变形 | 缺少viewport meta标签 |
检查head里有没有<meta name="viewport"> |
| 某些浏览器样式错乱 | 使用了未加前缀的新CSS属性 | 用Can I Use查兼容性并补前缀 |
| 列表数据重复显示 | Mock数据被原地修改且未清空旧列表 | 渲染前先innerHTML = "" |
| JS变量被其他脚本覆盖 | 函数/变量挂在全局作用域 | 用IIFE或ES Module包裹 |
排查时最忌讳的是“盲改”,直接让AI重新生成可能把之前改好的逻辑又弄坏。我的习惯是先在DevTools里确定问题发生在HTML、CSS还是JS层,再针对性地让AI修改对应模块,改完立刻用边界用例验证。这样既能节省时间,也能保证改动范围可控。
5. 这次实操后的一些真实体会
做完这个小项目,我最大的感受不是“前端要完了”,而是“重复劳动要完了”。真正值钱的不是会写div和click,而是知道页面为什么要这样设计、数据怎么流转、交互怎么才是好的。AI能30分钟生成一个原生页面,但它不知道这个页面背后的业务目标、用户习惯和上线后的维护成本。这些,仍然需要人来判断。
我也开始习惯把AI当成一个“随叫随到的结对编程伙伴”。每次生成完代码,我会先自己跑一遍主流程,再故意输入非法数据挑战它,确认没有问题后再交付。这个方法让我少踩了很多坑,也让我重新审视自己在团队里的定位:我不再是那个被需求追着赶的“切图仔”,而是那个告诉别人“我们可以用AI快速搭出原型,但上线方案需要仔细设计”的人。
如果你正在学前端,我的建议很简单:别慌,去学最基础的原生三件套,去多写代码,去尝试把一个AI生成的页面手工改到最好。这个过程比背十套面试题都有用。如果你已经是工作多年的前端老鸟,那更不用焦虑,把AI当成你的杠杆,你会发现一个页面从想法到落地之间的距离,从来没有这么短过。
