热门角色不仅是灵感来源,更是你的效率助手。通过精挑细选的角色提示词,你可以快速生成高质量内容、提升创作灵感,并找到最契合你需求的解决方案。让创作更轻松,让价值更直接!
我们根据不同用户需求,持续更新角色库,让你总能找到合适的灵感入口。
本提示词模板专为网站前端开发设计,能够根据用户需求生成完整的HTML、CSS和JavaScript代码。通过智能分析网站类型、设计风格和功能需求,自动构建响应式布局和交互功能,确保代码的规范性和可维护性。该模板特别适合快速原型开发、教学演示和中小企业官网搭建,支持多种主流设计风格和交互效果,输出代码可直接部署使用或作为进一步开发的基础框架。模板采用模块化设计思路,确保生成代码的结构清晰、语义准确,同时预留充分的定制空间。
这是一个为MVP展示页定制的、单文件即可运行的前端网站模板,采用简约现代设计风格,支持以下特性:
注意:A/B测试与分析仅提供前端支持示例(本地存储 + console日志),用于演示与验证,不包含任何外部请求或第三方脚本引用。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
<title>NovaFlow - 让产品从0到1更快验证 | MVP展示页</title>
<meta name="description" content="NovaFlow 帮助团队在一周内完成从原型到可用MVP的迭代闭环。更快验证、更轻交付、更好增长。" />
<meta name="theme-color" content="#0ea5e9" />
<link rel="canonical" href="https://example.com/" />
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:title" content="NovaFlow - 让产品从0到1更快验证">
<meta property="og:description" content="更快验证、更轻交付、更好增长。A/B测试、拖拽布局、报名表单、迭代公告、亮暗主题。">
<meta property="og:url" content="https://example.com/">
<!-- Twitter -->
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="NovaFlow - MVP展示页">
<meta name="twitter:description" content="一页搞定产品验证与增长必备组件。">
<!-- 结构化数据:SoftwareApplication + Organization -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"name": "NovaFlow",
"url": "https://example.com",
"logo": "https://example.com/logo.png"
},
{
"@type": "SoftwareApplication",
"name": "NovaFlow",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"description": "帮助团队在一周内完成从原型到MVP的验证闭环:A/B测试、拖拽布局、报名表单、迭代公告、亮暗主题。",
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "CNY" }
}
]
}
</script>
<!-- Analytics Slot(示例占位,不含外部引用):如需接入第三方分析,将脚本粘贴在此注释下方 -->
<!--
示例(请替换为你的供应商脚本,确保合法合规):
<script>
// your analytics code
</script>
-->
<style>
:root {
--bg: #ffffff;
--bg-soft: #f7fafc;
--text: #0f172a;
--muted: #475569;
--border: #e2e8f0;
--primary: #0ea5e9;
--primary-contrast: #ffffff;
--accent: #22c55e;
--warning: #f59e0b;
--card: #ffffff;
--shadow: 0 2px 10px rgba(0,0,0,.06);
--radius: 14px;
--focus: 0 0 0 3px rgba(14,165,233,.35);
}
[data-theme="dark"] {
--bg: #0b0f14;
--bg-soft: #0f1720;
--text: #e5e7eb;
--muted: #9ca3af;
--border: #1f2937;
--primary: #38bdf8;
--primary-contrast: #0b0f14;
--accent: #34d399;
--warning: #fbbf24;
--card: #0f1720;
--shadow: 0 4px 16px rgba(0,0,0,.35);
--focus: 0 0 0 3px rgba(56,189,248,.35);
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
color: var(--text);
background: radial-gradient(80rem 60rem at 20% -10%, rgba(14,165,233,.08), transparent 40%),
radial-gradient(60rem 40rem at 120% 10%, rgba(34,197,94,.07), transparent 40%),
var(--bg);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; }
.container {
width: 100%;
max-width: 1100px;
margin: 0 auto;
padding: 0 20px;
}
header.site-header {
position: sticky;
top: 0;
z-index: 50;
backdrop-filter: saturate(180%) blur(12px);
background: color-mix(in srgb, var(--bg) 85%, transparent);
border-bottom: 1px solid var(--border);
}
.nav {
display: flex; align-items: center; justify-content: space-between;
height: 64px;
}
.brand {
display: flex; align-items: center; gap: 10px; font-weight: 700;
}
.brand .logo {
width: 28px; height: 28px; border-radius: 8px;
background: linear-gradient(135deg, var(--primary), var(--accent));
box-shadow: var(--shadow);
}
nav ul { list-style: none; display: flex; gap: 18px; margin: 0; padding: 0; }
nav a { color: var(--muted); font-weight: 600; }
nav a:hover { color: var(--text); }
.actions { display: flex; gap: 10px; align-items: center; }
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: 8px;
height: 40px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--border);
background: var(--card); color: var(--text); box-shadow: var(--shadow);
cursor: pointer; font-weight: 600;
}
.btn:hover { transform: translateY(-1px); }
.btn:focus-visible { outline: none; box-shadow: var(--focus); }
.btn-primary { background: var(--primary); color: var(--primary-contrast); border-color: transparent; }
.btn-ghost { background: transparent; border-color: var(--border); }
.btn-icon { width: 40px; padding: 0; }
.badge {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px; border-radius: 999px; font-size: 12px;
border: 1px solid var(--border); background: var(--bg-soft); color: var(--muted);
}
/* Announcement bar */
.announcement {
background: linear-gradient(90deg, color-mix(in srgb, var(--primary) 25%, transparent), transparent);
border-bottom: 1px dashed var(--border);
color: var(--muted);
font-size: 14px;
}
.announcement .wrap {
display: flex; align-items: center; gap: 10px; justify-content: space-between;
padding: 8px 0;
}
.announcement .left { display: flex; align-items: center; gap: 8px; }
.announcement .close { all: unset; cursor: pointer; color: var(--muted); padding: 4px 8px; border-radius: 6px; }
.announcement .close:hover { background: var(--bg-soft); }
/* Modules */
main { padding: 32px 0 80px; }
section.module {
position: relative;
margin: 22px 0;
padding: 28px;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow);
}
section.module h2 {
margin: 0 0 14px;
font-size: 24px;
letter-spacing: .2px;
}
section.module .sub {
margin: 0 0 18px; color: var(--muted);
}
/* Drag handle + controls */
.module .drag-handle {
position: absolute; inset-inline-end: 10px; inset-block-start: 10px;
display: none; align-items: center; gap: 6px;
font-size: 12px; color: var(--muted);
padding: 6px 10px; border-radius: 8px; border: 1px dashed var(--border);
background: var(--bg-soft); user-select: none;
cursor: grab;
}
.customizing .module .drag-handle { display: inline-flex; }
.module-controls {
display: none; gap: 6px; position: absolute; inset-inline-end: 10px; inset-block-start: 48px;
}
.customizing .module-controls { display: inline-flex; }
.module-controls .ctrl {
height: 28px; width: 28px; border-radius: 8px; border: 1px solid var(--border);
background: var(--card); color: var(--muted); cursor: pointer;
}
.drag-placeholder {
border: 2px dashed var(--primary);
background: color-mix(in srgb, var(--primary) 8%, transparent);
min-height: 60px; border-radius: var(--radius);
margin: 22px 0;
}
.customizing .module { outline: 2px dashed transparent; transition: outline-color .2s; }
.customizing .module:focus-within { outline-color: color-mix(in srgb, var(--primary) 40%, transparent); }
/* Hero */
#hero { padding: 36px; display: grid; gap: 18px; }
#hero h1 { font-size: 34px; margin: 0; line-height: 1.2; letter-spacing: .2px; }
.hero-points { display: grid; gap: 10px; }
.hero-points li { list-style: none; display: flex; gap: 10px; align-items: baseline; color: var(--muted); }
.ctas { display: flex; gap: 10px; flex-wrap: wrap; padding-top: 6px; }
/* Features */
.features-grid {
display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px;
}
.feature-card {
grid-column: span 6;
border: 1px solid var(--border); border-radius: 14px; padding: 16px;
background: var(--bg);
}
.feature-card h3 { margin: 6px 0 6px; font-size: 18px; }
.feature-card p { margin: 0; color: var(--muted); }
/* Roadmap */
.roadmap {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
}
.road-col { border: 1px solid var(--border); border-radius: 12px; padding: 14px; background: var(--bg); }
.road-col h3 { margin: 0 0 8px; font-size: 16px; }
.road-col ul { margin: 0; padding-left: 18px; }
.tag { display: inline-block; font-size: 12px; padding: 2px 8px; border-radius: 999px; background: var(--bg-soft); border: 1px solid var(--border); color: var(--muted); }
/* Form */
form .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
form .row { display: grid; gap: 6px; }
label { font-weight: 600; }
input, select, textarea {
width: 100%; height: 40px; padding: 8px 10px; border-radius: 10px; border: 1px solid var(--border);
background: var(--bg); color: var(--text);
}
textarea { height: 100px; resize: vertical; }
.hint { font-size: 12px; color: var(--muted); }
.form-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.success {
display: none; margin-top: 12px; padding: 10px 12px; border-radius: 12px;
background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
color: color-mix(in srgb, var(--accent) 80%, #0b0f14);
}
.success.show { display: block; }
/* FAQ */
details { border: 1px solid var(--border); border-radius: 12px; padding: 10px 14px; background: var(--bg); }
details + details { margin-top: 10px; }
summary { cursor: pointer; font-weight: 600; }
details[open] { box-shadow: var(--shadow); }
/* Changelog */
.changelog-list { display: grid; gap: 10px; }
.change-item { border: 1px dashed var(--border); border-radius: 12px; padding: 12px; background: var(--bg); }
.change-item h3 { margin: 0 0 6px; font-size: 16px; }
.meta { color: var(--muted); font-size: 12px; }
footer {
border-top: 1px solid var(--border);
padding: 24px 0; color: var(--muted); font-size: 14px;
}
footer .row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
/* Responsive */
@media (max-width: 900px) {
.features-grid .feature-card { grid-column: span 12; }
form .grid { grid-template-columns: 1fr; }
.roadmap { grid-template-columns: 1fr; }
}
</style>
</head>
<body data-theme="auto">
<!-- 顶部迭代公告条(可关闭,持久化) -->
<div class="announcement" id="announcement" role="region" aria-label="迭代公告">
<div class="container">
<div class="wrap">
<div class="left">
<span class="badge">v0.4.2</span>
<span>新增:拖拽布局、主题偏好持久化、A/B测试变体</span>
</div>
<button class="close" id="close-announcement" aria-label="关闭公告">关闭</button>
</div>
</div>
</div>
<header class="site-header" role="banner">
<div class="container nav">
<div class="brand">
<span class="logo" aria-hidden="true"></span>
<span>NovaFlow</span>
<span class="badge" id="ab-badge" title="A/B测试变体">AB: A</span>
</div>
<nav aria-label="主导航">
<ul>
<li><a href="#hero">概述</a></li>
<li><a href="#features">功能</a></li>
<li><a href="#roadmap">路线图</a></li>
<li><a href="#signup">报名</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#changelog">公告</a></li>
</ul>
</nav>
<div class="actions">
<button class="btn btn-ghost" id="layout-toggle" aria-pressed="false">自定义布局</button>
<button class="btn btn-ghost" id="layout-reset" title="重置模块顺序">重置</button>
<button class="btn btn-icon" id="theme-toggle" title="切换主题" aria-label="切换主题">🌓</button>
</div>
</div>
</header>
<main class="container" id="main">
<!-- Hero 模块 -->
<section class="module" id="hero" data-module="hero" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<span class="badge">产品愿景</span>
<h1 id="hero-title">让产品从0到1更快验证</h1>
<p class="sub" id="hero-sub">
NovaFlow 将「洞察-构建-验证-迭代」压缩到一周内:所见即所得模块、A/B测试、表单收集、主题切换与公告管理,帮你用最小成本跑出最大结果。
</p>
<ul class="hero-points" aria-label="核心卖点">
<li>✅ 一页整合验证必需组件,减少上下游沟通成本</li>
<li>✅ A/B 测试内置,快速定位有效文案与CTA</li>
<li>✅ 拖拽布局 + 深色模式,提升审美与可用性</li>
<li>✅ 零依赖纯前端,复制即用,易于接入任意后端</li>
</ul>
<div class="ctas">
<a class="btn btn-primary" href="#signup" id="hero-cta">立即报名体验</a>
<a class="btn" href="#features">查看功能</a>
</div>
</section>
<!-- 功能列表 -->
<section class="module" id="features" data-module="features" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<h2>功能一览</h2>
<p class="sub">覆盖验证闭环的关键模块,低成本高效率。</p>
<div class="features-grid">
<article class="feature-card">
<span class="tag">交互</span>
<h3>A/B测试引擎</h3>
<p>URL参数/本地持久化两种分流方式,曝光与CTA点击事件就绪,可接入任意分析。</p>
</article>
<article class="feature-card">
<span class="tag">体验</span>
<h3>模块拖拽</h3>
<p>桌面端拖拽排序,移动端按钮上/下移;顺序本地持久化,实验排版更轻松。</p>
</article>
<article class="feature-card">
<span class="tag">品牌</span>
<h3>亮/暗主题</h3>
<p>三态:亮 / 暗 / 跟随系统;自动记忆偏好,夜间浏览舒适护眼。</p>
</article>
<article class="feature-card">
<span class="tag">增长</span>
<h3>报名与反馈</h3>
<p>姓名/邮箱/用途三要素收集,本地校验与成功反馈,轻松对接你的后端。</p>
</article>
<article class="feature-card">
<span class="tag">发布</span>
<h3>迭代公告</h3>
<p>顶部公告条 + 更新日志,让用户一路感知产品进步,增强信任。</p>
</article>
<article class="feature-card">
<span class="tag">SEO</span>
<h3>基础优化</h3>
<p>语义结构、元信息与结构化数据,社交卡片预设,助力被正确发现。</p>
</article>
</div>
</section>
<!-- 路线图 -->
<section class="module" id="roadmap" data-module="roadmap" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<h2>产品路线图</h2>
<p class="sub">Now / Next / Later,让方向清晰、节奏明确。</p>
<div class="roadmap" role="list">
<div class="road-col" role="listitem" aria-label="现在">
<h3>现在 <span class="tag">进行中</span></h3>
<ul>
<li>报名表单与校验完善</li>
<li>拖拽布局 + 移动端上/下移</li>
<li>A/B测试与曝光统计</li>
</ul>
</div>
<div class="road-col" role="listitem" aria-label="下一步">
<h3>下一步</h3>
<ul>
<li>可视化配置面板</li>
<li>内置数据可视化卡片</li>
<li>多语言与可访问性增强</li>
</ul>
</div>
<div class="road-col" role="listitem" aria-label="未来">
<h3>未来</h3>
<ul>
<li>服务端事件回传SDK</li>
<li>模板市场与生态扩展</li>
<li>插件化能力与团队协作</li>
</ul>
</div>
</div>
</section>
<!-- 报名与反馈表单 -->
<section class="module" id="signup" data-module="signup" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<h2>报名体验 / 反馈建议</h2>
<p class="sub">留下联系信息,我们会在首批可用时通知你,并邀请加入用户群。</p>
<form id="lead-form" novalidate>
<div class="grid">
<div class="row">
<label for="name">姓名</label>
<input id="name" name="name" type="text" placeholder="请输入姓名" required />
</div>
<div class="row">
<label for="email">邮箱</label>
<input id="email" name="email" type="email" placeholder="name@example.com" required />
</div>
</div>
<div class="row" style="margin-top:12px;">
<label for="usage">用途 / 使用场景</label>
<select id="usage" name="usage" required>
<option value="" selected disabled>请选择你的主要用途</option>
<option value="企业官网MVP">企业官网MVP</option>
<option value="产品展示页">产品展示页</option>
<option value="个人作品集">个人作品集</option>
<option value="教育培训演示">教育培训演示</option>
<option value="营销活动页">营销活动页</option>
<option value="其他">其他</option>
</select>
<span class="hint">我们将用于优化模板与优先支持。</span>
</div>
<div class="row" style="margin-top:12px;">
<label for="msg">补充需求(可选)</label>
<textarea id="msg" name="msg" placeholder="如需特定组件或API对接,请在此说明"></textarea>
</div>
<div class="form-actions" style="margin-top:14px;">
<button type="submit" class="btn btn-primary">提交报名</button>
<label class="hint"><input type="checkbox" id="agree" checked /> 我同意接收产品更新邮件</label>
</div>
<div class="success" id="form-success" role="status" aria-live="polite">
感谢提交!已记录你的信息(AB变体:<span id="submitted-variant">A</span>)。我们会尽快与你联系。
</div>
</form>
</section>
<!-- FAQ -->
<section class="module" id="faq" data-module="faq" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<h2>常见问题 FAQ</h2>
<details>
<summary>可以直接上线使用吗?</summary>
<div>可以。这是零依赖纯前端模板,支持移动端与桌面端。你可以直接部署到静态空间,后续再接后端即可。</div>
</details>
<details>
<summary>A/B 测试如何查看数据?</summary>
<div>模板内置曝光与CTA点击的console日志与本地存储。接入第三方分析时,将事件上报函数替换为你的SDK。</div>
</details>
<details>
<summary>拖拽排序是否会丢失?</summary>
<div>模块顺序会保存在浏览器本地(localStorage)。你也可以点击“重置”恢复默认顺序。</div>
</details>
<details>
<summary>表单数据保存在哪里?</summary>
<div>默认保存在本地存储以便演示。正式环境请改为提交到你的后端或Serverless函数。</div>
</details>
</section>
<!-- 迭代公告 / 更新日志 -->
<section class="module" id="changelog" data-module="changelog" tabindex="-1">
<div class="drag-handle" aria-hidden="true">⋮⋮ 拖拽模块</div>
<div class="module-controls" aria-hidden="true">
<button class="ctrl" data-move="up" title="上移">↑</button>
<button class="ctrl" data-move="down" title="下移">↓</button>
</div>
<h2>迭代公告</h2>
<p class="sub">持续小步快跑,快速汇报进展与方向。</p>
<div class="changelog-list" aria-label="更新列表">
<article class="change-item">
<h3>v0.4.2</h3>
<div class="meta">2025-10-08</div>
<ul>
<li>新增:模块拖拽 + 布局持久化</li>
<li>新增:亮/暗/系统主题切换</li>
<li>新增:A/B测试变体与曝光、点击埋点接口</li>
</ul>
</article>
<article class="change-item">
<h3>v0.4.1</h3>
<div class="meta">2025-09-23</div>
<ul>
<li>优化:表单校验与国际化预留</li>
<li>优化:移动端排版与触控区域</li>
</ul>
</article>
</div>
</section>
</main>
<footer role="contentinfo">
<div class="container">
<div class="row">
<div>© <span id="year"></span> NovaFlow · Made for fast MVP</div>
<div>
<span class="badge">主题:<span id="theme-state">auto</span></span>
</div>
</div>
</div>
</footer>
<!-- Analytics Slot(页面尾部占位) -->
<!-- 粘贴你的统计代码到此处(请确保合法合规并遵循隐私政策) -->
<script>
(function () {
const $ = (sel, root=document) => root.querySelector(sel);
const $$ = (sel, root=document) => Array.from(root.querySelectorAll(sel));
// ---------- 基础工具 ----------
const storage = {
get(key, fallback=null) {
try { const v = localStorage.getItem(key); return v ? JSON.parse(v) : fallback; } catch { return fallback; }
},
set(key, value) {
try { localStorage.setItem(key, JSON.stringify(value)); } catch {}
},
del(key) { try { localStorage.removeItem(key); } catch {} }
};
// ---------- Analytics Stub(示例) ----------
window.analytics = {
record(event, data={}) {
// 在此替换为你的分析SDK上报逻辑
console.log("[analytics]", event, data);
}
};
// ---------- 年份 ----------
$("#year").textContent = new Date().getFullYear();
// ---------- 主题切换 ----------
const themeKey = "nf_theme";
const themeStateEl = $("#theme-state");
const themeToggle = $("#theme-toggle");
function applyTheme(mode) {
const prefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
let actual = mode;
if (mode === "auto") {
actual = prefersDark ? "dark" : "light";
}
document.body.setAttribute("data-theme", actual);
themeStateEl.textContent = mode;
}
const savedTheme = storage.get(themeKey, "auto");
applyTheme(savedTheme);
themeToggle.addEventListener("click", () => {
const current = themeStateEl.textContent;
const next = current === "auto" ? "light" : current === "light" ? "dark" : "auto";
storage.set(themeKey, next);
applyTheme(next);
analytics.record("theme_change", { mode: next });
});
// ---------- 公告条 ----------
const ann = $("#announcement");
const closeAnn = $("#close-announcement");
const annKey = "nf_ann_closed_v042";
if (storage.get(annKey, false)) ann.style.display = "none";
closeAnn.addEventListener("click", () => {
ann.style.display = "none";
storage.set(annKey, true);
});
// ---------- A/B 测试 ----------
const abKey = "nf_ab_variant";
const urlParams = new URLSearchParams(location.search);
const urlAb = urlParams.get("ab");
const valid = (v) => v === "A" || v === "B";
let variant = storage.get(abKey, null);
if (valid(urlAb)) {
variant = urlAb;
storage.set(abKey, variant);
}
if (!valid(variant)) {
variant = Math.random() < 0.5 ? "A" : "B";
storage.set(abKey, variant);
}
document.body.classList.add("ab-" + variant.toLowerCase());
$("#ab-badge").textContent = "AB: " + variant;
// 应用变体文案
const heroTitle = $("#hero-title");
const heroSub = $("#hero-sub");
const heroCTA = $("#hero-cta");
if (variant === "A") {
heroTitle.textContent = "让产品从0到1更快验证";
heroSub.textContent = "NovaFlow 将「洞察-构建-验证-迭代」压缩到一周内:所见即所得模块、A/B测试、表单收集、主题切换与公告管理,帮你用最小成本跑出最大结果。";
heroCTA.textContent = "立即报名体验";
} else {
heroTitle.textContent = "用一页,跑通增长闭环";
heroSub.textContent = "把验证所需的关键环节装进一页:从认知到转化再到复访,用更少的时间验证更大的价值。";
heroCTA.textContent = "现在就开始";
}
// 曝光上报(示例)
analytics.record("ab_exposure", { variant, path: location.pathname });
// CTA 点击上报(示例)
heroCTA.addEventListener("click", () => {
analytics.record("cta_click", { variant, cta: heroCTA.textContent });
});
// ---------- 表单逻辑 ----------
const form = $("#lead-form");
const success = $("#form-success");
const submittedVariant = $("#submitted-variant");
form.addEventListener("submit", (e) => {
e.preventDefault();
const formData = new FormData(form);
const name = (formData.get("name") || "").trim();
const email = (formData.get("email") || "").trim();
const usage = formData.get("usage") || "";
const msg = (formData.get("msg") || "").trim();
const agree = $("#agree").checked;
// 简单校验
const emailOK = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
if (!name || !emailOK || !usage) {
alert("请完整填写姓名、合法邮箱与用途。");
return;
}
// 本地存储演示
const leadsKey = "nf_leads";
const leads = storage.get(leadsKey, []);
leads.push({ name, email, usage, msg, agree, ts: Date.now(), variant });
storage.set(leadsKey, leads);
submittedVariant.textContent = variant;
success.classList.add("show");
analytics.record("form_submit", { variant, usage });
form.reset();
});
// ---------- 模块拖拽与排序 ----------
const main = $("#main");
const modules = () => $$(".module", main);
const orderKey = "nf_module_order";
// 应用排序
const savedOrder = storage.get(orderKey, null);
if (Array.isArray(savedOrder) && savedOrder.length) {
const idSet = new Set(savedOrder);
modules()
.sort((a, b) => {
const ia = savedOrder.indexOf(a.id);
const ib = savedOrder.indexOf(b.id);
return (ia === -1 ? 999 : ia) - (ib === -1 ? 999 : ib);
})
.forEach(el => main.appendChild(el));
}
function persistOrder() {
const order = modules().map(m => m.id);
storage.set(orderKey, order);
}
// 自定义布局开关
const layoutToggle = $("#layout-toggle");
const layoutReset = $("#layout-reset");
let customizing = false;
layoutToggle.addEventListener("click", () => {
customizing = !customizing;
document.body.classList.toggle("customizing", customizing);
layoutToggle.setAttribute("aria-pressed", String(customizing));
modules().forEach(m => m.setAttribute("draggable", customizing ? "true" : "false"));
analytics.record("layout_customizing", { on: customizing });
});
layoutReset.addEventListener("click", () => {
// 恢复默认顺序(按DOM原始序)
storage.del(orderKey);
location.reload();
});
// 移动端辅助按钮(上/下移)
$$(".module-controls .ctrl").forEach(btn => {
btn.addEventListener("click", (e) => {
const mod = e.target.closest(".module");
if (!mod) return;
if (e.target.dataset.move === "up" && mod.previousElementSibling) {
main.insertBefore(mod, mod.previousElementSibling);
} else if (e.target.dataset.move === "down" && mod.nextElementSibling) {
const next = mod.nextElementSibling.nextElementSibling;
main.insertBefore(mod, next);
}
persistOrder();
});
});
// 桌面端拖拽
let dragging = null;
let placeholder = null;
function createPlaceholder(height) {
const ph = document.createElement("div");
ph.className = "drag-placeholder";
ph.style.height = height + "px";
return ph;
}
main.addEventListener("dragstart", (e) => {
const mod = e.target.closest(".module");
if (!customizing || !mod) return;
dragging = mod;
placeholder = createPlaceholder(mod.offsetHeight);
mod.style.opacity = "0.5";
analytics.record("module_drag_start", { id: mod.id });
});
main.addEventListener("dragend", (e) => {
if (!dragging) return;
dragging.style.opacity = "";
if (placeholder && placeholder.parentNode) {
placeholder.parentNode.replaceChild(dragging, placeholder);
}
dragging = null;
placeholder = null;
persistOrder();
analytics.record("module_drag_end", {});
});
main.addEventListener("dragover", (e) => {
if (!customizing || !dragging) return;
e.preventDefault();
const after = getDragAfterElement(main, e.clientY);
if (!placeholder) placeholder = createPlaceholder(dragging.offsetHeight);
if (after == null) {
main.appendChild(placeholder);
} else {
main.insertBefore(placeholder, after);
}
});
function getDragAfterElement(container, y) {
const els = modules().filter(el => el !== dragging);
let closest = { offset: Number.NEGATIVE_INFINITY, element: null };
els.forEach(child => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
closest = { offset, element: child };
}
});
return closest.element;
}
// ---------- 可访问性增强 ----------
// 键盘辅助:在自定义模式下,模块获得焦点时,按Alt+↑ / Alt+↓ 进行上/下移
main.addEventListener("keydown", (e) => {
if (!customizing || !e.target.classList.contains("module")) return;
if (e.altKey && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
e.preventDefault();
const mod = e.target;
if (e.key === "ArrowUp" && mod.previousElementSibling) {
main.insertBefore(mod, mod.previousElementSibling);
} else if (e.key === "ArrowDown" && mod.nextElementSibling) {
const next = mod.nextElementSibling.nextElementSibling;
main.insertBefore(mod, next);
}
persistOrder();
analytics.record("module_reorder_keyboard", { id: mod.id });
}
});
})();
</script>
</body>
</html>
/* 已内联至HTML的<style>中;若需拆分外链,请将以下内容保存为 styles.css 并移除HTML内联样式。 */
/* 见HTML代码块中的<style>,内容完全一致 */
// 已内联至HTML的<script>中;若需拆分外链,请将以下内容保存为 app.js 并在HTML底部以 <script src="app.js"></script> 引入。
// 见HTML代码块中的<script>,内容完全一致
本地预览
A/B测试
模块拖拽
主题切换
表单
迭代公告
SEO与分析脚本位
UI定制
A/B扩展
表单与合规
性能优化
可访问性
国际化
如需我根据你的品牌与产品信息进一步定制文案、配色与模块结构,请提供产品名称、目标用户、核心场景与竞品对比等信息。
这是一个教学示例页,面向前端入门与进阶教学场景。它具备以下特性与技术实现:
技术栈与规范:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="description" content="前端教学示例页:标准化结构、一键生成、布局切换、响应式断点、作业提交与导出讲义。">
<title>前端教学示例页 · 标准化结构与响应式布局演示</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- 跳转主内容的无障碍链接 -->
<a class="skip-link" href="#main">跳转到主内容</a>
<header class="site-header" role="banner">
<div class="container header-inner">
<a class="brand" href="#" aria-label="网站品牌标识">教学示例页</a>
<button id="menuToggle" class="menu-toggle" aria-expanded="false" aria-controls="siteNav">菜单</button>
<nav id="siteNav" class="site-nav" aria-label="主导航">
<ul>
<li><a href="#hero">简介</a></li>
<li><a href="#a11y">无障碍与语义化</a></li>
<li><a href="#layout">布局演示</a></li>
<li><a href="#codeDoc">代码讲解</a></li>
<li><a href="#assignment">作业提交</a></li>
<li><a href="#export">导出工具</a></li>
</ul>
</nav>
</div>
</header>
<main id="main" tabindex="-1">
<!-- 主视觉区 -->
<section id="hero" class="hero" aria-label="主视觉与快速操作">
<div class="container hero-inner">
<div class="hero-text">
<h1>前端教学示例:结构、布局与交互</h1>
<p>一键生成标准化页面结构,演示响应式栅格与断点注释,切换Grid / Flex布局方案,提供代码片段讲解与作业提交/导出工具。</p>
<div class="hero-actions">
<button id="generateStructureBtn" class="btn primary">一键生成标准化结构</button>
<button id="exportHandoutBtn" class="btn">导出讲义(Markdown)</button>
</div>
</div>
<div class="hero-art" aria-hidden="true">
<!-- 内联SVG,避免外部资源 -->
<svg width="220" height="140" viewBox="0 0 220 140" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="教学示意图">
<rect x="5" y="5" width="210" height="130" rx="10" fill="#E6F0FF" stroke="#2B6CB0" stroke-width="2"/>
<rect x="15" y="20" width="190" height="20" rx="4" fill="#CDE2FF"/>
<rect x="15" y="50" width="90" height="70" rx="6" fill="#D9F2E6"/>
<rect x="115" y="50" width="90" height="70" rx="6" fill="#FFEFD2"/>
<text x="110" y="35" text-anchor="middle" font-size="12" fill="#2B6CB0">Nav / Hero / Grid / Footer</text>
</svg>
</div>
</div>
<div class="container">
<div id="structurePreview" class="structure-preview" aria-live="polite" aria-atomic="true"></div>
</div>
</section>
<!-- 无障碍与语义化提示 -->
<section id="a11y" class="section">
<div class="container">
<h2>无障碍与语义化提示</h2>
<ul class="a11y-list">
<li>使用语义化标签:header、nav、main、section、article、footer。</li>
<li>为交互控件添加可访问性属性:aria-label、aria-controls、aria-live、aria-expanded。</li>
<li>提供“跳转主内容”链接,确保键盘导航与焦点可见。</li>
<li>表单使用label显式关联输入框,错误提示与说明文本可被读屏识别。</li>
<li>颜色对比充足,状态变化不只依赖颜色;提供可视化焦点样式。</li>
</ul>
</div>
</section>
<!-- 布局演示 -->
<section id="layout" class="section">
<div class="container">
<div class="section-head">
<h2>响应式布局演示(栅格与断点)</h2>
<p>选择不同布局方案并查看代码片段与断点注释。栅格示例在小屏 1 列,中屏 2 列,大屏 3 列。</p>
</div>
<div class="controls" role="group" aria-label="布局切换控制">
<div class="control-group">
<span class="label">布局方案:</span>
<label><input type="radio" name="layoutMode" value="grid" checked> Grid 栅格</label>
<label><input type="radio" name="layoutMode" value="flex"> Flex 弹性</label>
</div>
<div class="control-group">
<label><input type="checkbox" id="showBreakpoints"> 显示断点辅助栏</label>
</div>
<div class="control-group">
<button id="resetDataBtn" class="btn">重置示例数据</button>
</div>
</div>
<div id="breakpointBar" class="breakpoint-bar" aria-hidden="true">
<div class="container">
<strong>断点参考:</strong>
<span>SM ≥ 640px</span>
<span>MD ≥ 960px</span>
<span>LG ≥ 1200px(容器最大宽度)</span>
</div>
</div>
<div id="layoutWrapper" class="layout-wrapper layout-grid">
<div id="cardContainer" class="cards" aria-live="polite" aria-busy="false">
<!-- JS渲染示例卡片 -->
</div>
</div>
</div>
</section>
<!-- 代码讲解 -->
<section id="codeDoc" class="section">
<div class="container">
<div class="section-head">
<h2>代码片段讲解</h2>
<p>可复制 HTML / CSS 片段,配套注释,便于课堂讲解与自学复盘。</p>
</div>
<div class="code-tabs" role="tablist" aria-label="代码片段标签">
<button class="tab-btn active" data-target="htmlSnippet" role="tab" aria-selected="true">HTML片段</button>
<button class="tab-btn" data-target="cssSnippet" role="tab" aria-selected="false">CSS片段</button>
<button id="copySnippetBtn" class="btn small">复制当前片段</button>
</div>
<div class="code-panels">
<pre id="htmlSnippet" class="code-block" aria-label="HTML代码片段"><code></code></pre>
<pre id="cssSnippet" class="code-block hidden" aria-label="CSS代码片段"><code></code></pre>
</div>
</div>
</section>
<!-- 作业提交 -->
<section id="assignment" class="section">
<div class="container">
<h2>作业提交表单与评分占位</h2>
<form id="assignmentForm" class="form" novalidate aria-labelledby="assignmentTitle">
<div class="form-grid">
<div class="form-item">
<label for="studentName">姓名</label>
<input id="studentName" name="studentName" type="text" required placeholder="例如:张三" aria-describedby="nameHelp">
<small id="nameHelp" class="muted">使用真实姓名,便于确认成绩。</small>
</div>
<div class="form-item">
<label for="studentEmail">邮箱</label>
<input id="studentEmail" name="studentEmail" type="email" required placeholder="example@domain.com">
</div>
<div class="form-item">
<label for="assignmentTitle">作业标题</label>
<input id="assignmentTitle" name="assignmentTitle" type="text" required placeholder="响应式布局练习">
</div>
<div class="form-item">
<label for="assignmentLink">作品链接</label>
<input id="assignmentLink" name="assignmentLink" type="url" placeholder="https://example.com/demo" aria-describedby="linkHelp">
<small id="linkHelp" class="muted">可填写在线预览地址或仓库链接。</small>
</div>
<div class="form-item">
<label for="assignmentFile">上传文件(可选)</label>
<input id="assignmentFile" name="assignmentFile" type="file" aria-describedby="fileHelp">
<small id="fileHelp" class="muted">本地预览用,不会上传到服务器。</small>
</div>
<div class="form-item form-item--full">
<label for="assignmentDesc">作业说明</label>
<textarea id="assignmentDesc" name="assignmentDesc" rows="4" maxlength="500" placeholder="简要说明你的设计思路与实现细节…" aria-describedby="descCount"></textarea>
<small id="descCount" class="muted" aria-live="polite">0 / 500</small>
</div>
<div class="form-item">
<label><input id="agreePolicy" type="checkbox" required> 我已阅读并同意课堂提交规范</label>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn primary">提交作业</button>
<button type="reset" class="btn">清空表单</button>
<button type="button" id="exportFormDataBtn" class="btn">导出表单数据(JSON)</button>
</div>
<div id="formErrors" class="form-errors" aria-live="assertive"></div>
</form>
<div class="submissions">
<h3>提交列表(评分占位)</h3>
<ul id="submissionList" class="submission-list">
<!-- JS添加条目 -->
</ul>
</div>
</div>
</section>
<!-- 导出工具 -->
<section id="export" class="section">
<div class="container">
<h2>导出代码与讲义</h2>
<p class="muted">可导出当前页面快照(内联CSS/JS),或分别导出HTML/CSS/JS源文件与课堂讲义。</p>
<div class="export-actions">
<button id="exportHTMLBtn" class="btn">导出 HTML</button>
<button id="exportCSSBtn" class="btn">导出 CSS</button>
<button id="exportJSBtn" class="btn">导出 JS</button>
<button id="exportSnapshotBtn" class="btn">导出页面快照(自包含)</button>
</div>
</div>
</section>
</main>
<footer class="site-footer" role="contentinfo">
<div class="container footer-inner">
<p>© 2025 教学示例页。用于教学演示,遵循 Web 标准与中国法律法规。</p>
<nav aria-label="页脚导航">
<a href="#hero">回到顶部</a>
</nav>
</div>
</footer>
<!-- 辅助:无障碍播报区域 -->
<div id="announce" class="sr-only" aria-live="polite" aria-atomic="true"></div>
<script defer src="script.js"></script>
</body>
</html>
/* 基础主题变量与重置 */
:root{
--bg: #ffffff;
--text: #1a1a1a;
--muted: #6b7280;
--primary: #2B6CB0; /* 教学友好蓝 */
--accent: #10B981; /* 成功绿 */
--warn: #D97706; /* 提醒橙 */
--surface: #f6f7fb;
--border: #e5e7eb;
--radius: 10px;
--shadow: 0 6px 20px rgba(0,0,0,0.08);
/* 容器与断点 */
--maxw: 1200px;
--bp-sm: 640px; /* SM:小屏断点,≥640px 开始两列 */
--bp-md: 960px; /* MD:中屏断点,≥960px 开始三列 */
}
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
font-family: system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Microsoft YaHei", sans-serif;
color:var(--text);
background:var(--bg);
line-height:1.6;
}
img{max-width:100%;display:block}
a{color:var(--primary);text-decoration:none}
a:hover{text-decoration:underline}
/* 可见焦点(无障碍) */
:focus-visible{
outline:3px solid #93C5FD;
outline-offset:2px;
}
/* 容器与通用区块 */
.container{max-width:var(--maxw);margin:0 auto;padding:0 16px}
.section{padding:48px 0}
.section-head h2{margin:0 0 8px}
.section-head p{color:var(--muted);margin:0 0 24px}
/* 跳转主内容 */
.skip-link{
position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;
}
.skip-link:focus{
position:fixed;left:16px;top:16px;width:auto;height:auto;padding:8px 12px;
background:#111;color:#fff;border-radius:6px;z-index:1000;
}
/* 头部导航 */
.site-header{background:#f8fbff;border-bottom:1px solid var(--border)}
.header-inner{display:flex;align-items:center;gap:16px;padding:12px 0}
.brand{font-weight:700;color:var(--primary)}
.menu-toggle{
margin-left:auto;
padding:8px 12px;border:1px solid var(--border);background:#fff;border-radius:8px;cursor:pointer;
}
.site-nav ul{
display:flex;gap:16px;list-style:none;margin:0;padding:0;
}
.site-nav a{padding:8px;border-radius:8px}
.site-nav a:hover{background:#eef6ff}
@media (max-width: 720px){
.menu-toggle{order:2}
.site-nav{display:none;order:3}
.site-nav.open{display:block}
.site-nav ul{flex-direction:column;padding:8px 0}
}
/* 主视觉 */
.hero{padding:40px 0 16px;background:linear-gradient(180deg,#F0F7FF,#fff)}
.hero-inner{display:grid;grid-template-columns:1fr 260px;gap:24px;align-items:center}
.hero-text h1{margin:0 0 8px}
.hero-text p{margin:0 0 16px;color:var(--muted)}
.hero-actions{display:flex;gap:12px;flex-wrap:wrap}
.hero-art{justify-self:end}
.structure-preview{
margin-top:16px;padding:16px;border:1px dashed var(--border);border-radius:var(--radius);background:var(--surface);
}
@media (max-width: 780px){
.hero-inner{grid-template-columns:1fr}
.hero-art{justify-self:start}
}
/* 按钮 */
.btn{
appearance:none;border:1px solid var(--border);background:#fff;color:var(--text);
padding:10px 14px;border-radius:10px;cursor:pointer;box-shadow:var(--shadow);
}
.btn:hover{background:#f2f6ff}
.btn.primary{background:var(--primary);border-color:transparent;color:#fff}
.btn.primary:hover{filter:brightness(1.05)}
.btn.small{padding:6px 10px;font-size:14px}
/* 布局演示控制区 */
.controls{
display:flex;flex-wrap:wrap;gap:16px;align-items:center;margin:8px 0 16px;
}
.control-group{display:flex;gap:12px;align-items:center}
.label{color:#374151}
/* 断点辅助栏(可开关显示) */
.breakpoint-bar{
position:sticky;top:0;z-index:500;background:#111;color:#fff;padding:8px 0;margin-bottom:12px;
display:none;
}
.breakpoint-bar .container{display:flex;gap:20px;align-items:center}
.breakpoint-bar .container span{opacity:0.85}
/* 布局外层:用于切换布局方案类名 */
.layout-wrapper{}
/* 卡片列表通用样式 */
.cards{gap:16px}
.card{
background:#fff;border:1px solid var(--border);border-radius:12px;padding:16px;box-shadow:var(--shadow);
display:flex;flex-direction:column;gap:8px;
}
.card-header{display:flex;align-items:center;gap:12px}
.card-title{font-weight:700;margin:0}
.card-desc{color:var(--muted);margin:0}
.card-tags{display:flex;gap:8px;flex-wrap:wrap}
.tag{font-size:12px;color:#0F766E;background:#E6FFFA;border:1px solid #99F6E4;border-radius:999px;padding:2px 8px}
.card-actions{margin-top:auto;display:flex;gap:8px}
/* 布局方案 A:Grid 栅格 */
.layout-grid .cards{
display:grid;
grid-template-columns: 1fr; /* 默认:小屏 1 列 */
}
/* 断点注释:
@media (min-width: 640px) => SM:两列
@media (min-width: 960px) => MD:三列
*/
@media (min-width: 640px){
.layout-grid .cards{ grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 960px){
.layout-grid .cards{ grid-template-columns: repeat(3, 1fr); }
}
/* 布局方案 B:Flex 弹性 */
.layout-flex .cards{
display:flex; flex-wrap:wrap;
}
.layout-flex .card{
width:100%;
}
@media (min-width: 640px){
.layout-flex .card{ width: calc(50% - 8px); } /* 两列,减去gap一半 */
}
@media (min-width: 960px){
.layout-flex .card{ width: calc(33.333% - 10.7px); } /* 三列 */
}
/* 代码区 */
.code-tabs{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.tab-btn{padding:8px 12px;border:1px solid var(--border);border-radius:8px;background:#fff;cursor:pointer}
.tab-btn.active{background:#EEF6FF;border-color:#BFDBFE}
.code-block{
border:1px solid var(--border);border-radius:12px;background:#0B1020;color:#E5EDFF;
padding:16px;overflow:auto;box-shadow:var(--shadow);max-height:60vh;
}
.code-block.hidden{display:none}
.code-block code{font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}
/* 表单 */
.form-grid{
display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:12px;
}
.form-item{display:flex;flex-direction:column;gap:8px}
.form-item--full{grid-column:1 / -1}
label{font-weight:600}
input[type="text"], input[type="email"], input[type="url"], input[type="file"], textarea{
width:100%;padding:10px;border:1px solid var(--border);border-radius:8px;background:#fff;
}
input:focus, textarea:focus{border-color:#93C5FD;box-shadow:0 0 0 3px #DBEAFE}
.form-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:4px}
.form-errors{margin-top:12px;color:#B91C1C;background:#FEF2F2;border:1px solid #FECACA;padding:10px;border-radius:8px;display:none}
.muted{color:var(--muted)}
/* 提交列表 */
.submission-list{
list-style:none;margin:12px 0 0;padding:0;display:grid;gap:12px;
}
.submission-item{
border:1px solid var(--border);border-radius:10px;padding:12px;background:#fff;box-shadow:var(--shadow);
display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center;
}
.submission-meta{color:var(--muted);font-size:14px}
.grade-placeholder{color:#374151;background:#FFF7ED;border:1px dashed #FED7AA;padding:6px 8px;border-radius:8px}
/* 页脚 */
.site-footer{margin-top:32px;border-top:1px solid var(--border);background:#fafafa}
.footer-inner{display:flex;justify-content:space-between;align-items:center;padding:16px 0}
/* 小屏优化 */
@media (max-width: 780px){
.form-grid{grid-template-columns:1fr}
.submission-item{grid-template-columns:1fr}
}
/* 教学示例页交互脚本
- 一键生成标准化结构
- 布局方案切换(Grid/Flex)与代码片段更新
- 示例数据渲染/重置
- 作业提交表单验证与“待评分”占位
- 导出代码与讲义/页面快照
- 无障碍:ARIA 播报、可见焦点、键盘友好菜单
*/
(function(){
const qs = (s, p=document) => p.querySelector(s);
const qsa = (s, p=document) => Array.from(p.querySelectorAll(s));
const announce = (msg) => {
const el = qs('#announce');
el.textContent = msg;
// 清空以便下一次读屏触发
setTimeout(()=>{ el.textContent = ''; }, 1200);
};
// 示例数据(可按需扩展或替换)
const sampleItems = [
{title:'导航与信息架构', desc:'演示 header/nav/main/footer 的标准化结构。', tags:['HTML5','语义化']},
{title:'主视觉模块', desc:'教学友好主视觉区,呼出核心CTA与示意图。', tags:['UX','Hero']},
{title:'Grid 栅格', desc:'小屏1列,中屏2列,大屏3列的响应式示例。', tags:['CSS Grid','响应式']},
{title:'Flex 弹性布局', desc:'等宽卡片换行布局,配合断点调整列数。', tags:['Flexbox','布局']},
{title:'无障碍实践', desc:'跳转主内容、焦点可见、ARIA提示等。', tags:['a11y','可访问性']},
{title:'代码片段讲解', desc:'HTML/CSS片段切换与复制,配套注释。', tags:['教学','代码']},
{title:'作业提交表单', desc:'必填项校验、字符计数与数据导出。', tags:['表单','验证']},
{title:'评分占位', desc:'提交列表内展示“待评分”状态。', tags:['评分','占位']},
{title:'示例数据填充', desc:'内置卡片数据,用于课堂展示。', tags:['数据','演示']},
{title:'导出工具', desc:'导出HTML/CSS/JS与讲义Markdown。', tags:['导出','工具']},
{title:'移动端适配', desc:'在窄屏下菜单折叠、表单单列。', tags:['移动端','适配']},
{title:'性能与规范', desc:'简洁结构,无外部依赖,安全可靠。', tags:['规范','性能']},
];
// 结构生成的标准化模板
const STANDARD_STRUCTURE_HTML = `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>标准化页面结构示例</title>
</head>
<body>
<a class="skip-link" href="#main">跳转到主内容</a>
<header role="banner">
<nav aria-label="主导航">
<ul>
<li><a href="#hero">简介</a></li>
<li><a href="#content">内容区</a></li>
<li><a href="#footer">页脚</a></li>
</ul>
</nav>
</header>
<main id="main">
<section id="hero" aria-label="主视觉">
<h1>主视觉标题</h1>
<p>副标题或引导语</p>
<button>主要操作</button>
</section>
<section id="content" aria-label="内容区">
<article>
<h2>模块标题</h2>
<p>模块内容文本示例。</p>
</article>
</section>
</main>
<footer id="footer" role="contentinfo">
<small>© 示例页脚信息</small>
</footer>
</body>
</html>`;
// 代码片段:HTML(卡片列表)
const CARDS_HTML_SNIPPET = `<section class="cards-demo">
<div class="cards">
<article class="card">
<header class="card-header">
<h3 class="card-title">示例标题</h3>
</header>
<p class="card-desc">卡片描述文字……</p>
<div class="card-tags">
<span class="tag">标签</span>
</div>
<div class="card-actions">
<button class="btn small">查看</button>
<button class="btn small">收藏</button>
</div>
</article>
<!-- 更多卡片… -->
</div>
</section>`;
// 代码片段:CSS(Grid/Flex)
const GRID_CSS_SNIPPET = `/* 布局方案 A:Grid 栅格 */
.layout-grid .cards{ display:grid; grid-template-columns:1fr; gap:16px; }
/* SM ≥ 640px:两列 */
@media (min-width: 640px){ .layout-grid .cards{ grid-template-columns: repeat(2, 1fr); } }
/* MD ≥ 960px:三列 */
@media (min-width: 960px){ .layout-grid .cards{ grid-template-columns: repeat(3, 1fr); } }`;
const FLEX_CSS_SNIPPET = `/* 布局方案 B:Flex 弹性 */
.layout-flex .cards{ display:flex; flex-wrap:wrap; gap:16px; }
.layout-flex .card{ width:100%; }
/* SM ≥ 640px:两列 */
@media (min-width: 640px){ .layout-flex .card{ width: calc(50% - 8px); } }
/* MD ≥ 960px:三列 */
@media (min-width: 960px){ .layout-flex .card{ width: calc(33.333% - 10.7px); } }`;
// 菜单折叠
const menuToggle = qs('#menuToggle');
const siteNav = qs('#siteNav');
menuToggle?.addEventListener('click', ()=>{
const opened = siteNav.classList.toggle('open');
menuToggle.setAttribute('aria-expanded', opened ? 'true' : 'false');
});
// 一键生成标准化结构
const structurePreview = qs('#structurePreview');
const generateStructureBtn = qs('#generateStructureBtn');
generateStructureBtn?.addEventListener('click', ()=>{
structurePreview.innerHTML = `
<div class="structure-box">
<h3>标准化结构(预览 + 可复制)</h3>
<p class="muted">包含导航、主视觉、内容区、页脚与跳转主内容链接。</p>
<pre class="code-block"><code>${escapeHtml(STANDARD_STRUCTURE_HTML)}</code></pre>
<button class="btn small" id="copyStructureBtn">复制结构代码</button>
</div>
`;
qs('#copyStructureBtn', structurePreview)?.addEventListener('click', ()=>{
copyText(STANDARD_STRUCTURE_HTML);
announce('标准化结构代码已复制');
});
setActiveTab('htmlSnippet');
setSnippet('html', STANDARD_STRUCTURE_HTML);
announce('标准化结构已生成并展示');
});
// 布局与示例数据渲染
const cardContainer = qs('#cardContainer');
const layoutWrapper = qs('#layoutWrapper');
const resetDataBtn = qs('#resetDataBtn');
function renderCards(){
cardContainer.setAttribute('aria-busy', 'true');
cardContainer.innerHTML = sampleItems.map(createCardHTML).join('');
cardContainer.setAttribute('aria-busy', 'false');
}
function createCardHTML(item){
const icon = `<svg width="36" height="36" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<rect x="1.5" y="1.5" width="33" height="33" rx="8" fill="#EEF6FF" stroke="#2B6CB0"/>
<path d="M8 18h20M18 8v20" stroke="#2B6CB0" stroke-width="2"/>
</svg>`;
return `<article class="card">
<header class="card-header">${icon}<h3 class="card-title">${escapeHtml(item.title)}</h3></header>
<p class="card-desc">${escapeHtml(item.desc)}</p>
<div class="card-tags">${item.tags.map(t => `<span class="tag">${escapeHtml(t)}</span>`).join('')}</div>
<div class="card-actions">
<button class="btn small" aria-label="查看 ${escapeHtml(item.title)}">查看</button>
<button class="btn small" aria-label="收藏 ${escapeHtml(item.title)}">收藏</button>
</div>
</article>`;
}
resetDataBtn?.addEventListener('click', ()=>{
renderCards();
announce('示例数据已重置');
});
// 布局切换与代码片段
const htmlBlock = qs('#htmlSnippet code');
const cssBlock = qs('#cssSnippet code');
const tabButtons = qsa('.tab-btn');
const copySnippetBtn = qs('#copySnippetBtn');
const showBreakpoints = qs('#showBreakpoints');
const breakpointBar = qs('#breakpointBar');
function setSnippet(type, content){
if(type === 'html'){
htmlBlock.textContent = content;
}else if(type === 'css'){
cssBlock.textContent = content;
}
}
function setActiveTab(id){
tabButtons.forEach(btn=>{
const target = btn.dataset.target;
const active = target === id;
btn.classList.toggle('active', active);
btn.setAttribute('aria-selected', active ? 'true' : 'false');
qs('#'+target).classList.toggle('hidden', !active);
});
}
tabButtons.forEach(btn=>{
btn.addEventListener('click', ()=>{
setActiveTab(btn.dataset.target);
});
});
// 初始化:渲染卡片、默认布局与片段
renderCards();
setSnippet('html', CARDS_HTML_SNIPPET);
setSnippet('css', GRID_CSS_SNIPPET);
// 布局模式切换
qsa('input[name="layoutMode"]').forEach(radio=>{
radio.addEventListener('change', ()=>{
const val = radio.value;
layoutWrapper.classList.toggle('layout-grid', val === 'grid');
layoutWrapper.classList.toggle('layout-flex', val === 'flex');
setActiveTab('cssSnippet');
setSnippet('css', val === 'grid' ? GRID_CSS_SNIPPET : FLEX_CSS_SNIPPET);
announce(`布局已切换为 ${val === 'grid' ? 'Grid 栅格' : 'Flex 弹性'}`);
});
});
// 断点辅助栏开关
showBreakpoints?.addEventListener('change', ()=>{
const on = showBreakpoints.checked;
breakpointBar.style.display = on ? 'block' : 'none';
announce(on ? '已显示断点辅助栏' : '已隐藏断点辅助栏');
});
// 复制当前片段
copySnippetBtn?.addEventListener('click', ()=>{
const active = tabButtons.find(btn=>btn.classList.contains('active'))?.dataset.target;
const text = active === 'cssSnippet' ? cssBlock.textContent : htmlBlock.textContent;
copyText(text);
announce('代码片段已复制到剪贴板');
});
// 表单:字符计数与提交验证
const form = qs('#assignmentForm');
const desc = qs('#assignmentDesc');
const descCount = qs('#descCount');
const formErrors = qs('#formErrors');
const submissionList = qs('#submissionList');
const exportFormDataBtn = qs('#exportFormDataBtn');
desc?.addEventListener('input', ()=>{
descCount.textContent = `${desc.value.length} / ${desc.maxLength}`;
});
form?.addEventListener('submit', (e)=>{
e.preventDefault();
formErrors.style.display = 'none';
if(!form.checkValidity()){
showFormErrors();
return;
}
const data = new FormData(form);
const entry = {
name: data.get('studentName')?.toString().trim(),
email: data.get('studentEmail')?.toString().trim(),
title: data.get('assignmentTitle')?.toString().trim(),
link: data.get('assignmentLink')?.toString().trim(),
desc: data.get('assignmentDesc')?.toString().trim(),
ts: new Date().toISOString(),
grade: null // 待评分
};
addSubmission(entry);
form.reset();
descCount.textContent = `0 / ${desc.maxLength}`;
announce('作业已提交,状态为待评分');
});
function showFormErrors(){
const invalids = qsa('#assignmentForm input:invalid, #assignmentForm textarea:invalid');
const names = invalids.map(el=> qs(`label[for="${el.id}"]`)?.textContent || el.name);
formErrors.innerHTML = `<strong>请检查以下字段:</strong> ${names.join('、')}`;
formErrors.style.display = 'block';
invalids[0]?.focus();
announce('表单校验失败,请完善必填项');
}
function addSubmission(entry){
const li = document.createElement('li');
li.className = 'submission-item';
li.innerHTML = `
<div>
<strong>${escapeHtml(entry.title)}</strong>
<div class="submission-meta">
<span>${escapeHtml(entry.name)} · ${escapeHtml(entry.email)}</span>
${entry.link ? ` · <a href="${escapeAttr(entry.link)}" target="_blank" rel="noopener">作品链接</a>` : ''}
</div>
</div>
<div class="grade-placeholder" role="status" aria-label="评分占位">待评分</div>
`;
submissionList.prepend(li);
}
// 导出表单数据
exportFormDataBtn?.addEventListener('click', ()=>{
const items = qsa('.submission-item').map(li=>{
const title = li.querySelector('strong')?.textContent || '';
const meta = li.querySelector('.submission-meta')?.textContent || '';
const grade = li.querySelector('.grade-placeholder')?.textContent || '待评分';
return { title, meta, grade };
});
downloadText(JSON.stringify({ exportedAt: new Date().toISOString(), submissions: items }, null, 2), 'submissions.json', 'application/json');
announce('已导出提交列表数据');
});
// 导出讲义(Markdown)
const exportHandoutBtn = qs('#exportHandoutBtn');
exportHandoutBtn?.addEventListener('click', ()=>{
const md = buildHandoutMarkdown();
downloadText(md, '前端教学讲义.md', 'text/markdown');
announce('讲义已导出');
});
// 导出代码与页面快照(自包含)
const exportHTMLBtn = qs('#exportHTMLBtn');
const exportCSSBtn = qs('#exportCSSBtn');
const exportJSBtn = qs('#exportJSBtn');
const exportSnapshotBtn = qs('#exportSnapshotBtn');
exportHTMLBtn?.addEventListener('click', ()=>{
downloadText(HTML_SOURCE, 'index.html', 'text/html');
announce('HTML 源文件已导出');
});
exportCSSBtn?.addEventListener('click', ()=>{
downloadText(CSS_SOURCE, 'styles.css', 'text/css');
announce('CSS 源文件已导出');
});
exportJSBtn?.addEventListener('click', ()=>{
downloadText(JS_SOURCE, 'script.js', 'text/javascript');
announce('JS 源文件已导出');
});
exportSnapshotBtn?.addEventListener('click', ()=>{
const snapshot = `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>页面快照</title><style>${CSS_SOURCE}</style></head><body>${document.body.outerHTML}<script>${JS_SOURCE}</script></body></html>`;
downloadText(snapshot, 'snapshot.html', 'text/html');
announce('已导出页面快照(内联CSS/JS)');
});
// 工具函数
function escapeHtml(str=''){
return str.replace(/[&<>"']/g, s=>({ '&':'&', '<':'<', '>':'>', '"':'"', "'":''' }[s]));
}
function escapeAttr(str=''){
return str.replace(/"/g, '"');
}
function copyText(text){
if(navigator.clipboard && window.isSecureContext){
navigator.clipboard.writeText(text).catch(()=>fallbackCopy(text));
}else{
fallbackCopy(text);
}
}
function fallbackCopy(text){
const ta = document.createElement('textarea');
ta.value = text; document.body.appendChild(ta);
ta.select(); try{ document.execCommand('copy'); }catch(e){}
document.body.removeChild(ta);
}
function downloadText(text, filename, type='text/plain'){
const blob = new Blob([text], {type});
const url = URL.createObjectURL(blob);
const a = document.createElement('a'); a.href = url; a.download = filename;
document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
}
function buildHandoutMarkdown(){
return [
'# 前端教学讲义',
'',
'## 目标',
'- 理解 HTML5 语义化结构(header/nav/main/section/footer)。',
'- 掌握响应式布局(Grid 与 Flex)与断点设计。',
'- 学会表单可访问性与基础校验,了解数据导出。',
'',
'## 标准化结构示例',
'```html',
STANDARD_STRUCTURE_HTML.replace(/```/g, '\\`\\`\\`'),
'```',
'',
'## 布局片段(Grid)',
'```css',
GRID_CSS_SNIPPET,
'```',
'',
'## 布局片段(Flex)',
'```css',
FLEX_CSS_SNIPPET,
'```',
'',
'## 练习任务',
'1. 在 Grid 布局下,调整列间距与卡片样式,使其更符合你的项目风格。',
'2. 尝试将 Flex 方案改造为瀑布流或不等高卡片的均衡排列(提示:align-content、order)。',
'3. 为作业表单增加更多校验规则(如标题长度、URL格式等),并在提交列表中显示部分字段。',
'',
'## 无障碍要点',
'- 跳转主内容链接与可见焦点。',
'- ARIA 属性:aria-live、aria-label、aria-controls、aria-expanded。',
'- 表单标签与错误提示可被读屏识别。',
'',
'## 参考建议',
'- 将断点命名与设计系统(Design Tokens)绑定,保持一致性。',
'- 代码片段讲解与项目实践相结合,强化吸收。',
'',
'(本讲义由教学示例页自动生成)'
].join('\n');
}
// 以下三段源文件字符串用于“导出代码”按钮生成文件。
// 为了演示的自包含导出功能,它们与当前页面的 HTML/CSS/JS 内容保持一致。
const HTML_SOURCE = `<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="description" content="前端教学示例页:标准化结构、一键生成、布局切换、响应式断点、作业提交与导出讲义。">
<title>前端教学示例页 · 标准化结构与响应式布局演示</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a class="skip-link" href="#main">跳转到主内容</a>
<header class="site-header" role="banner">
<div class="container header-inner">
<a class="brand" href="#" aria-label="网站品牌标识">教学示例页</a>
<button id="menuToggle" class="menu-toggle" aria-expanded="false" aria-controls="siteNav">菜单</button>
<nav id="siteNav" class="site-nav" aria-label="主导航">
<ul>
<li><a href="#hero">简介</a></li>
<li><a href="#a11y">无障碍与语义化</a></li>
<li><a href="#layout">布局演示</a></li>
<li><a href="#codeDoc">代码讲解</a></li>
<li><a href="#assignment">作业提交</a></li>
<li><a href="#export">导出工具</a></li>
</ul>
</nav>
</div>
</header>
<main id="main" tabindex="-1">
<section id="hero" class="hero" aria-label="主视觉与快速操作">
<div class="container hero-inner">
<div class="hero-text">
<h1>前端教学示例:结构、布局与交互</h1>
<p>一键生成标准化页面结构,演示响应式栅格与断点注释,切换Grid / Flex布局方案,提供代码片段讲解与作业提交/导出工具。</p>
<div class="hero-actions">
<button id="generateStructureBtn" class="btn primary">一键生成标准化结构</button>
<button id="exportHandoutBtn" class="btn">导出讲义(Markdown)</button>
</div>
</div>
<div class="hero-art" aria-hidden="true">
<svg width="220" height="140" viewBox="0 0 220 140" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="教学示意图">
<rect x="5" y="5" width="210" height="130" rx="10" fill="#E6F0FF" stroke="#2B6CB0" stroke-width="2"/>
<rect x="15" y="20" width="190" height="20" rx="4" fill="#CDE2FF"/>
<rect x="15" y="50" width="90" height="70" rx="6" fill="#D9F2E6"/>
<rect x="115" y="50" width="90" height="70" rx="6" fill="#FFEFD2"/>
<text x="110" y="35" text-anchor="middle" font-size="12" fill="#2B6CB0">Nav / Hero / Grid / Footer</text>
</svg>
</div>
</div>
<div class="container">
<div id="structurePreview" class="structure-preview" aria-live="polite" aria-atomic="true"></div>
</div>
</section>
<section id="a11y" class="section">
<div class="container">
<h2>无障碍与语义化提示</h2>
<ul class="a11y-list">
<li>使用语义化标签:header、nav、main、section、article、footer。</li>
<li>为交互控件添加可访问性属性:aria-label、aria-controls、aria-live、aria-expanded。</li>
<li>提供“跳转主内容”链接,确保键盘导航与焦点可见。</li>
<li>表单使用label显式关联输入框,错误提示与说明文本可被读屏识别。</li>
<li>颜色对比充足,状态变化不只依赖颜色;提供可视化焦点样式。</li>
</ul>
</div>
</section>
<section id="layout" class="section">
<div class="container">
<div class="section-head">
<h2>响应式布局演示(栅格与断点)</h2>
<p>选择不同布局方案并查看代码片段与断点注释。栅格示例在小屏 1 列,中屏 2 列,大屏 3 列。</p>
</div>
<div class="controls" role="group" aria-label="布局切换控制">
<div class="control-group">
<span class="label">布局方案:</span>
<label><input type="radio" name="layoutMode" value="grid" checked> Grid 栅格</label>
<label><input type="radio" name="layoutMode" value="flex"> Flex 弹性</label>
</div>
<div class="control-group">
<label><input type="checkbox" id="showBreakpoints"> 显示断点辅助栏</label>
</div>
<div class="control-group">
<button id="resetDataBtn" class="btn">重置示例数据</button>
</div>
</div>
<div id="breakpointBar" class="breakpoint-bar" aria-hidden="true">
<div class="container">
<strong>断点参考:</strong>
<span>SM ≥ 640px</span>
<span>MD ≥ 960px</span>
<span>LG ≥ 1200px(容器最大宽度)</span>
</div>
</div>
<div id="layoutWrapper" class="layout-wrapper layout-grid">
<div id="cardContainer" class="cards" aria-live="polite" aria-busy="false"></div>
</div>
</div>
</section>
<section id="codeDoc" class="section">
<div class="container">
<div class="section-head">
<h2>代码片段讲解</h2>
<p>可复制 HTML / CSS 片段,配套注释,便于课堂讲解与自学复盘。</p>
</div>
<div class="code-tabs" role="tablist" aria-label="代码片段标签">
<button class="tab-btn active" data-target="htmlSnippet" role="tab" aria-selected="true">HTML片段</button>
<button class="tab-btn" data-target="cssSnippet" role="tab" aria-selected="false">CSS片段</button>
<button id="copySnippetBtn" class="btn small">复制当前片段</button>
</div>
<div class="code-panels">
<pre id="htmlSnippet" class="code-block" aria-label="HTML代码片段"><code></code></pre>
<pre id="cssSnippet" class="code-block hidden" aria-label="CSS代码片段"><code></code></pre>
</div>
</div>
</section>
<section id="assignment" class="section">
<div class="container">
<h2>作业提交表单与评分占位</h2>
<form id="assignmentForm" class="form" novalidate aria-labelledby="assignmentTitle">
<div class="form-grid">
<div class="form-item">
<label for="studentName">姓名</label>
<input id="studentName" name="studentName" type="text" required placeholder="例如:张三" aria-describedby="nameHelp">
<small id="nameHelp" class="muted">使用真实姓名,便于确认成绩。</small>
</div>
<div class="form-item">
<label for="studentEmail">邮箱</label>
<input id="studentEmail" name="studentEmail" type="email" required placeholder="example@domain.com">
</div>
<div class="form-item">
<label for="assignmentTitle">作业标题</label>
<input id="assignmentTitle" name="assignmentTitle" type="text" required placeholder="响应式布局练习">
</div>
<div class="form-item">
<label for="assignmentLink">作品链接</label>
<input id="assignmentLink" name="assignmentLink" type="url" placeholder="https://example.com/demo" aria-describedby="linkHelp">
<small id="linkHelp" class="muted">可填写在线预览地址或仓库链接。</small>
</div>
<div class="form-item">
<label for="assignmentFile">上传文件(可选)</label>
<input id="assignmentFile" name="assignmentFile" type="file" aria-describedby="fileHelp">
<small id="fileHelp" class="muted">本地预览用,不会上传到服务器。</small>
</div>
<div class="form-item form-item--full">
<label for="assignmentDesc">作业说明</label>
<textarea id="assignmentDesc" name="assignmentDesc" rows="4" maxlength="500" placeholder="简要说明你的设计思路与实现细节…" aria-describedby="descCount"></textarea>
<small id="descCount" class="muted" aria-live="polite">0 / 500</small>
</div>
<div class="form-item">
<label><input id="agreePolicy" type="checkbox" required> 我已阅读并同意课堂提交规范</label>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn primary">提交作业</button>
<button type="reset" class="btn">清空表单</button>
<button type="button" id="exportFormDataBtn" class="btn">导出表单数据(JSON)</button>
</div>
<div id="formErrors" class="form-errors" aria-live="assertive"></div>
</form>
<div class="submissions">
<h3>提交列表(评分占位)</h3>
<ul id="submissionList" class="submission-list"></ul>
</div>
</div>
</section>
<section id="export" class="section">
<div class="container">
<h2>导出代码与讲义</h2>
<p class="muted">可导出当前页面快照(内联CSS/JS),或分别导出HTML/CSS/JS源文件与课堂讲义。</p>
<div class="export-actions">
<button id="exportHTMLBtn" class="btn">导出 HTML</button>
<button id="exportCSSBtn" class="btn">导出 CSS</button>
<button id="exportJSBtn" class="btn">导出 JS</button>
<button id="exportSnapshotBtn" class="btn">导出页面快照(自包含)</button>
</div>
</div>
</section>
</main>
<footer class="site-footer" role="contentinfo">
<div class="container footer-inner">
<p>© 2025 教学示例页。用于教学演示,遵循 Web 标准与中国法律法规。</p>
<nav aria-label="页脚导航"><a href="#hero">回到顶部</a></nav>
</div>
</footer>
<div id="announce" class="sr-only" aria-live="polite" aria-atomic="true"></div>
<script defer src="script.js"></script>
</body>
</html>`;
const CSS_SOURCE = `/* 此处 CSS 内容与页面 styles.css 一致,详见本项目 CSS块 */\n` + document.querySelector('link[rel="stylesheet"]') ? '' : ''; // 占位(在线快照会内联真实CSS)
// 由于当前环境无法直接读取外部CSS文件,这里提供教学占位:
// 实际使用时,导出按钮会生成空CSS(请用上方“CSS样式”块内容保存为 styles.css)
// 如果您将本页面的 CSS 内联进快照,snapshot 导出中将包含完整样式。
const JS_SOURCE = `/* 此处 JS 内容与页面 script.js 一致,详见本项目 JS块 */\n` + (function(){return ''})();
// 提示:为避免浏览器安全限制,这里不从外部 CSS/JS 文件读取。
// 教学建议:请将“CSS样式”与“JavaScript功能”块分别保存为 styles.css 与 script.js。
// 导出 HTML 按钮会生成一个 index.html,其 <link rel="stylesheet"> 与 <script src> 指向上述文件。
})();
说明:出于浏览器安全限制,脚本中无法直接读取外部 styles.css/script.js 的内容,因此 JS 中的 CSS_SOURCE/JS_SOURCE使用占位。请使用下方“使用说明”将本页 CSS 和 JS分别保存为文件后,本页的导出按钮即可生成指向这些文件的 HTML;“导出页面快照(自包含)”会将当前页面的 DOM、CSS 与 JS内联打包(在真实运行环境中,可将 CSS_SOURCE/JS_SOURCE替换为真实内容或由构建工具注入)。
开发与运行
教学演示流程建议
浏览器兼容性
无障碍与安全
视觉主题
布局扩展
交互增强
教学导出
无障碍深度优化
如需我将导出功能改为打包ZIP或将CSS/JS真实内联到导出快照,请告知您的运行环境与限制(本地/服务器/构建工具),我将提供相应方案。
用它快速搭建MVP展示页与功能说明页,收集报名或反馈,随时调整模块与风格,缩短验证周期并加速市场测试。
无需外包即可生成企业官网与活动落地页,保持品牌视觉一致,快速添加表单与轮播,促成线索收集与转化。
课堂或训练营中一键生成标准化页面,讲解页面结构与响应式布局,布置作业与示例,提高教学效率与学习成效。
将“前端网站全栈生成器”打造成你的即用型网站搭建助理:只需输入网站类型、设计风格与功能需求,即可一次性生成可上线的页面(含HTML、CSS、JavaScript),自动适配移动与桌面端,满足企业官网、活动落地页、作品集与教学演示等场景。核心目标是显著缩短从想法到成品的周期、降低沟通与外包成本、保障代码质量与后续扩展,让用户从首次试用迅速感知效率红利,并通过解锁高级能力实现持续付费。
将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。
把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。
在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。
免费获取高级提示词-优惠即将到期