Creation chat
yihtech
请帮我制定一份管理系统的前端规范
07-05 02:43
暂无回复
No comments yet
登录 后可以评论
Assistant
这是为您生成的一份管理系统前端规范的HTML页面,它清晰展示了编码规范、组件设计和主题切换等核心要求。
(HTML code has been generated and updated; see above for the current version.)
### 规范文档与交互示例
这份页面既是规范说明,也是一个可交互的待办应用示例,帮助您理解各项要求如何落地。
* **规范概览**:页面顶部以卡片网格的形式,清晰列出了“编码规范”、“安全 & 交互”、“持久化 & 状态”和“可访问性 & 响应式”四大核心规范要点,便于团队快速查阅和对齐。
* **交互示例**:下方的“待办示例”模块演示了规范的具体应用。您可以通过表单添加待办,点击待办项前的图标切换完成状态,或使用“清空所有”按钮进行批量操作。所有数据都会自动保存到浏览器的 `localStorage` 中,刷新页面后状态依然保留。
* **操作反馈**:页面为所有可交互元素(按钮、链接)提供了 hover 和 focus 样式反馈。同时,在“清空所有”等关键操作时会弹出自定义确认弹窗,替代了浏览器原生的 `alert`,视觉风格更统一。
▼ Code
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理系统 · 前端规范</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>tailwind.config = { darkMode: 'class' }</script>
</head>
<body class="min-h-screen bg-slate-50 dark:bg-slate-900 text-slate-700 dark:text-slate-200">
<!-- ===== 主题切换按钮 (固定右上角) ===== -->
<button id="theme-toggle-btn" class="fixed top-4 right-4 z-10 p-2 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 transition-colors flex items-center justify-center" aria-label="Toggle theme" onclick="toggleTheme()">
<svg id="icon-moon" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998z"/></svg>
<svg id="icon-sun" class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"></path></svg>
</button>
<script>
function toggleTheme(){ var el=document.documentElement; var isDark=!el.classList.contains('dark'); el.classList.toggle('dark',isDark); localStorage.setItem('theme',isDark?'dark':'light'); applyTheme(isDark); }
function applyTheme(isDark){ document.getElementById('icon-moon').style.display=isDark?'none':'block'; document.getElementById('icon-sun').style.display=isDark?'block':'none'; }
document.addEventListener('DOMContentLoaded',function(){ var saved=localStorage.getItem('theme'); var isDark=saved==='dark'||(!saved&&window.matchMedia('(prefers-color-scheme: dark)').matches); document.documentElement.classList.toggle('dark',isDark); applyTheme(isDark); });
</script>
<!-- ===== 自定义弹窗 (用于提示/确认) ===== -->
<div id="custom-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 hidden" aria-hidden="true">
<div class="rounded-xl bg-white dark:bg-slate-800 p-6 shadow-xl max-w-sm w-full border border-slate-200 dark:border-slate-700">
<p id="custom-modal-msg" class="text-slate-700 dark:text-slate-200 mb-4"></p>
<button type="button" onclick="hideModal()" class="w-full rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600">确定</button>
</div>
</div>
<script>
function showModal(msg){ var el=document.getElementById('custom-modal'); document.getElementById('custom-modal-msg').textContent=msg||''; el.classList.remove('hidden'); }
function hideModal(){ document.getElementById('custom-modal').classList.add('hidden'); }
</script>
<!-- ===== 主内容 ===== -->
<main class="max-w-5xl mx-auto px-4 py-12 md:py-16">
<!-- 头部 -->
<header class="mb-12">
<h1 class="text-4xl md:text-5xl font-extrabold text-slate-900 dark:text-slate-100 tracking-tight">管理系统前端规范</h1>
<p class="mt-3 text-lg text-slate-600 dark:text-slate-400">基于现代蓝 · 响应式 · 可复用组件体系</p>
</header>
<!-- 规范概览卡片网格 -->
<section class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-16">
<!-- 卡片 1 -->
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-md border border-slate-200 dark:border-slate-700 p-6 transition-shadow hover:shadow-lg">
<div class="flex items-center gap-3 mb-4">
<span class="flex items-center justify-center w-10 h-10 rounded-lg bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6h16.5M3.75 12h16.5m-16.5 6h16.5"/></svg></span>
<h2 class="text-xl font-semibold text-slate-900 dark:text-slate-100">编码规范</h2>
</div>
<ul class="space-y-2 text-sm text-slate-600 dark:text-slate-300">
<li>✓ 语义化 HTML5 (header, main, section, nav)</li>
<li>✓ Tailwind CSS 响应式 (sm/md/lg)</li>
<li>✓ 组件化思维,复用卡片、表格、表单</li>
<li>✓ 所有交互使用 click + touch-action: manipulation</li>
<li>✓ dark 模式全面覆盖 (dark:bg-slate-800 等)</li>
</ul>
</div>
<!-- 卡片 2 -->
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-md border border-slate-200 dark:border-slate-700 p-6 transition-shadow hover:shadow-lg">
<div class="flex items-center gap-3 mb-4">
<span class="flex items-center justify-center w-10 h-10 rounded-lg bg-emerald-100 dark:bg-emerald-900/40 text-emerald-600 dark:text-emerald-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z"/></svg></span>
<h2 class="text-xl font-semibold text-slate-900 dark:text-slate-100">安全 & 交互</h2>
</div>
<ul class="space-y-2 text-sm text-slate-600 dark:text-slate-300">
<li>✓ 表单使用 JS 拦截 submit (preventDefault)</li>
<li>✓ 自定义弹窗代替 alert/confirm (showModal)</li>
<li>✓ 移动端触摸优化 (touch-action: manipulation)</li>
<li>✓ 所有按钮/链接有 hover/focus 反馈</li>
<li>✓ 避免依赖顶层导航 (target="_blank")</li>
</ul>
</div>
<!-- 卡片 3 -->
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-md border border-slate-200 dark:border-slate-700 p-6 transition-shadow hover:shadow-lg">
<div class="flex items-center gap-3 mb-4">
<span class="flex items-center justify-center w-10 h-10 rounded-lg bg-amber-100 dark:bg-amber-900/40 text-amber-600 dark:text-amber-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg></span>
<h2 class="text-xl font-semibold text-slate-900 dark:text-slate-100">持久化 & 状态</h2>
</div>
<ul class="space-y-2 text-sm text-slate-600 dark:text-slate-300">
<li>✓ localStorage 存储用户偏好/草稿</li>
<li>✓ 页面加载自动恢复上次状态</li>
<li>✓ 主题切换持久化 (dark/light)</li>
<li>✓ 控制台关键操作日志 (console.log)</li>
<li>✓ 可恢复的待办/表单数据</li>
</ul>
</div>
<!-- 卡片 4 -->
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-md border border-slate-200 dark:border-slate-700 p-6 transition-shadow hover:shadow-lg">
<div class="flex items-center gap-3 mb-4">
<span class="flex items-center justify-center w-10 h-10 rounded-lg bg-violet-100 dark:bg-violet-900/40 text-violet-600 dark:text-violet-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.53 16.122a3 3 0 0 0-5.78 1.128 2.25 2.25 0 0 0 2.4 2.245 4.5 4.5 0 0 0 8.4-2.245c0-.399-.078-.78-.22-1.128m0 0a15.998 15.998 0 0 0 3.388-1.62m-5.043-.025a15.994 15.994 0 0 1 1.622-3.395m3.42 3.42a15.995 15.995 0 0 0 4.764-4.648l3.876-5.814a1.151 1.151 0 0 0-1.597-1.597L14.146 6.32a15.996 15.996 0 0 0-4.649 4.763m3.42 3.42a6.776 6.776 0 0 0-3.42-3.42"/></svg></span>
<h2 class="text-xl font-semibold text-slate-900 dark:text-slate-100">可访问性 & 响应式</h2>
</div>
<ul class="space-y-2 text-sm text-slate-600 dark:text-slate-300">
<li>✓ 移动端优先,min-h-screen 显式高度</li>
<li>✓ aria-label, role, focus 管理</li>
<li>✓ 图片使用 object-cover + 占位 (picsum)</li>
<li>✓ 小游戏使用 Canvas + touch-action:none</li>
<li>✓ 字体/间距/留白一致</li>
</ul>
</div>
</section>
<!-- 组件示例区:待办列表 (展示交互、持久化、表单) -->
<section class="bg-white dark:bg-slate-800 rounded-2xl shadow-md border border-slate-200 dark:border-slate-700 p-6 md:p-8 mb-12">
<div class="flex items-center gap-3 mb-6">
<span class="flex items-center justify-center w-10 h-10 rounded-lg bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-400"><svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z"/></svg></span>
<h2 class="text-2xl font-bold text-slate-900 dark:text-slate-100">待办示例 · 带持久化</h2>
</div>
<!-- 表单 -->
<form id="todo-form" class="flex flex-col sm:flex-row gap-3 mb-6">
<input type="text" id="todo-input" placeholder="输入新待办…" class="flex-1 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-4 py-2.5 text-sm text-slate-700 dark:text-slate-200 placeholder-slate-400 dark:placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400" required>
<button type="submit" class="rounded-lg bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white px-5 py-2.5 text-sm font-medium transition flex items-center justify-center gap-1 touch-action:manipulation">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/></svg>
添加
</button>
</form>
<!-- 待办列表 -->
<ul id="todo-list" class="space-y-2">
<!-- 由 JS 动态渲染 -->
</ul>
<!-- 统计 & 操作 -->
<div class="flex flex-wrap items-center justify-between mt-6 pt-4 border-t border-slate-200 dark:border-slate-700 text-sm text-slate-500 dark:text-slate-400">
<span id="todo-count">0 项待办</span>
<button id="clear-all-btn" class="text-amber-600 dark:text-amber-400 hover:underline font-medium">清空所有</button>
</div>
</section>
<!-- 提示 Console 日志可用 -->
<footer class="text-center text-xs text-slate-400 dark:text-slate-500 border-t border-slate-200 dark:border-slate-700 pt-6">
<p>💡 预览区右下角有 Console 面板 · 所有操作均记录日志</p>
<p class="mt-1">规范版本 1.0 · 基于现代蓝配色</p>
</footer>
</main>
<script>
// ========== 待办模块 ==========
(function() {
const STORAGE_KEY = 'vibe_todo_demo';
const form = document.getElementById('todo-form');
const input = document.getElementById('todo-input');
const list = document.getElementById('todo-list');
const countSpan = document.getElementById('todo-count');
const clearBtn = document.getElementById('clear-all-btn');
// 读取或初始化
let todos = [];
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) todos = JSON.parse(stored);
} catch(e) { console.warn('读取待办失败', e); }
// 渲染
function render() {
list.innerHTML = '';
if (todos.length === 0) {
list.innerHTML = '<li class="text-slate-400 dark:text-slate-500 text-center py-6 italic">暂无待办,添加一条吧</li>';
} else {
todos.forEach((todo, index) => {
const li = document.createElement('li');
li.className = 'flex items-center justify-between gap-3 px-4 py-3 rounded-lg bg-slate-50 dark:bg-slate-700/60 border border-slate-200 dark:border-slate-600 transition';
li.innerHTML = `
<span class="flex-1 text-sm ${todo.done ? 'line-through text-slate-400 dark:text-slate-500' : 'text-slate-700 dark:text-slate-200'}">${escapeHtml(todo.text)}</span>
<div class="flex items-center gap-2">
<button class="toggle-btn text-emerald-600 dark:text-emerald-400 hover:text-emerald-800 dark:hover:text-emerald-300 p-1 rounded-md transition touch-action:manipulation" data-index="${index}" aria-label="切换完成">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/></svg>
</button>
<button class="delete-btn text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 p-1 rounded-md transition touch-action:manipulation" data-index="${index}" aria-label="删除待办">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/></svg>
</button>
</div>
`;
list.appendChild(li);
});
}
countSpan.textContent = `${todos.length} 项待办`;
// 持久化
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
console.log('[待办] 当前列表长度:', todos.length, todos.map(t=>t.text).join(', '));
}
// 简单转义
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 添加待办
function addTodo(text) {
if (!text.trim()) return;
todos.push({ text: text.trim(), done: false });
render();
console.log('[待办] 添加:', text.trim());
}
// 切换完成
function toggleDone(index) {
if (todos[index]) {
todos[index].done = !todos[index].done;
render();
console.log('[待办] 切换完成:', todos[index].text, todos[index].done);
}
}
// 删除
function deleteTodo(index) {
if (todos[index]) {
const removed = todos[index].text;
todos.splice(index, 1);
render();
console.log('[待办] 删除:', removed);
}
}
// 清空
function clearAll() {
if (todos.length === 0) return;
showModal('确定要清空所有待办吗?');
// 利用自定义弹窗的确定按钮做清空:监听弹窗确定按钮点击
// 但弹窗确定按钮已绑定 hideModal,需要额外逻辑
const modalBtn = document.querySelector('#custom-modal button');
const originalClick = modalBtn.onclick;
modalBtn.onclick = function() {
todos = [];
render();
console.log('[待办] 清空所有');
hideModal();
modalBtn.onclick = originalClick; // 恢复
};
}
// 事件绑定
form.addEventListener('submit', function(e) {
e.preventDefault();
const val = input.value.trim();
if (val) {
addTodo(val);
input.value = '';
} else {
showModal('请输入待办内容');
}
});
// 事件代理 (toggle / delete)
list.addEventListener('click', function(e) {
const toggleBtn = e.target.closest('.toggle-btn');
const deleteBtn = e.target.closest('.delete-btn');
if (toggleBtn) {
const index = parseInt(toggleBtn.dataset.index, 10);
toggleDone(index);
} else if (deleteBtn) {
const index = parseInt(deleteBtn.dataset.index, 10);
deleteTodo(index);
}
});
// 清空按钮
clearBtn.addEventListener('click', clearAll);
// 初始渲染
render();
console.log('[待办] 模块初始化完成');
})();
</script>
<!-- 确保移动端触摸时无延迟 -->
<style>
button, a, .touch-action\:manipulation { touch-action: manipulation; }
/* 自定义弹窗过渡 */
#custom-modal { transition: opacity 0.2s; }
#custom-modal.hidden { display: none; }
/* 列表按钮 */
.toggle-btn, .delete-btn { touch-action: manipulation; }
</style>
</body>
</html>
07-05 02:51
暂无回复
No comments yet
登录 后可以评论
Comments
暂无回复
No comments yet
登录 后可以评论