Vibe Coding一人即团队系列16: 基于PRD与Skills的UI界面自动化生成实践

纲要

  • Skills(智能技能包)概念与作用
  • Skills 安装与配置
    • 通过自然语言操作
    • 通过 CCTswitch 管理工具安装
  • 基于 PRD 文档与 Skills 的界面生成流程
  • 项目初始化与 CLAUDE.md 配置
  • 迭代优化与问题修复
  • 推荐 Skills 仓库与资源

技术背景与核心概念

在传统软件开发流程中,从产品需求文档(PRD)到最终用户界面,通常需要经历美术设计、UI/UX 设计、前端开发等多个环节。对于小型团队或个人开发者而言,美术设计资源往往缺失,导致界面生成成为效率瓶颈。

Anthropic 推出的 Skills(智能技能包)机制,为解决该问题提供了新思路。Skills 可理解为 AI 助手的可扩展功能模块,每个 Skill 包含特定领域的指令、脚本与资源文件。通过加载合适的 Skills,AI 助手能够获取特定领域的专业知识与操作能力,从而在缺乏美术设计人员的情况下,依据 PRD 文档自动生成具备基础视觉风格与功能完整性的 UI 页面。

Skills 安装与配置

Skills 概述

Skills 是包含指令、脚本与资源的文件夹,支持全局安装或项目级局部安装,并可在运行时动态加载。官方 Skills 仓库位于 github.com/anthropics/skills,其中包含大量官方与社区贡献的 Skills

安装 Skills 并非数量越多越好。过多的 Skills 可能引发指令冲突或上下文干扰,通常建议根据实际需求选择 10-20 个常用 Skills 即可。

安装方式一:通过自然语言操作

在支持 Skills 的 AI 对话环境中,可直接使用自然语言指令进行安装与卸载。

安装示例指令

请帮我安装 skill: anthropic/art

卸载示例指令

请帮我卸载 skill: anthropic/art

查看已安装列表

请以表格形式显示本地已安装的所有 skills 列表

注意事项:

  1. 执行安装/卸载操作时,建议逐条确认,避免自动执行误操作。
  2. 若安装超时或出现网络问题,可检查网络代理设置或切换地域节点。
  3. 若自然语言方式安装失败,可切换至管理工具方式。

安装方式二:通过 CCTswitch 管理工具

CCTswitch 是一款可视化的 Skills 管理工具,支持仓库添加、技能安装、卸载与启用/禁用管理。

操作步骤

  1. 打开 CCTswitch 界面,点击顶部 Skills 按钮进入管理面板。
  2. 添加官方仓库
    • 进入 仓库管理 页面。
    • 点击 添加仓库,输入官方仓库地址 github.com/anthropics/skills
    • 保存后,系统将自动识别仓库中的可用技能列表。
  3. 安装技能
    • 在主面板中找到目标技能(如 artdesign)。
    • 点击 安装 按钮,等待安装完成。
  4. 启用/禁用技能
    • 在技能列表中,通过勾选控制该技能是否在当前 AI 环境中启用。

目录树示例(安装后的本地技能存储结构)

~/.claude/skills/
├── anthropic/
│   ├── art/
│   │   ├── skill.md
│   │   └── scripts/
│   ├── design/
│   │   ├── skill.md
│   │   └── templates/
│   └── sq/
│       ├── skill.md
│       └── resources/
└── custom/
    └── my-skill/
        └── skill.md

基于 PRD 的界面生成流程

整体工作流

产品需求文档 PRD

加载 Skills

是否包含美术设计类 Skills?

AI 自动分析 PRD 并生成 UI

AI 基于通用规则生成 UI

生成 HTML/CSS/JS 代码

本地预览与验证

是否存在问题?

AI 迭代修复

项目初始化与配置

完成

核心操作指令

在具备 Skills 环境的 AI 对话中,可通过以下指令启动界面生成:

请根据 @需求文档.md 生成一个网站界面,若本地有合适的美术设计类 skills,请合理使用。

或直接使用特定 Skill 命令:

/anthropic:art 请根据 @需求文档.md 生成 UI 界面

AI 执行过程解析

  1. 需求分析阶段

    • AI 读取 PRD 文档内容,提取功能模块、数据模型、页面结构等关键信息。
    • 该阶段相当于传统开发中的需求评审与功能拆解。
  2. 设计阶段

    • AI 调用 artdesignSkills,生成页面布局、配色方案、组件样式。
    • 该阶段模拟了美术设计师的创作过程,但完全自动化完成。
  3. 编码阶段

    • AI 自动生成完整的 HTML 文件,内嵌 CSS 样式与 JavaScript 逻辑。
    • 代码生成遵循 PRD 中定义的功能规则,包括表单验证、本地数据缓存等。
  4. 验证与迭代

    • 生成的页面可在浏览器中直接打开预览。
    • 若发现乱码、布局异常或功能缺失,可通过自然语言指令要求 AI 修复。

实际生成效果说明

通过该流程生成的页面具备以下特征:

  • 视觉风格:基于 art Skill 的美术指导,页面配色协调、布局规整。
  • 功能完整性:涵盖首页、统计面板、账户管理等核心模块,符合 PRD 定义。
  • 数据持久化:前端采用浏览器本地缓存(localStorage)实现数据存储,支持增删改操作。
  • 响应式基础:页面适配基本屏幕尺寸,后续可进一步优化多端适配。
功能模块实现方式数据存储
首页概览HTML + CSS 卡片布局
数据统计JavaScript 动态计算localStorage 读取
账户管理表单 + 列表渲染localStorage 增删改
本地缓存localStorage API浏览器本地

项目初始化与配置

为确保 AI 助手能够更好地理解项目上下文,建议在项目根目录执行初始化操作,生成 CLAUDE.md 配置文件。

初始化指令

请初始化当前项目,创建 CLAUDE.md 核心配置文件。

生成的 CLAUDE.md 内容结构

# 项目指引

## 项目结构
- 纯 HTML 文件,无需构建流程
- 所有代码位于单个 HTML 文件中,便于快速迭代

## 数据模型
- 使用 localStorage 进行数据持久化
- 数据结构与 PRD 中定义的数据模型保持一致

## 开发注意事项
- 页面样式需保持与 art skill 生成的视觉规范一致
- 功能变更需同步更新 PRD 文档

推荐 Skills 仓库

以下社区仓库提供了丰富的 Skills 资源,可根据实际需求选择性安装:

仓库名称地址推荐安装技能
anthropics/skillsgithub.com/anthropics/skillsart, design, docx, pdf, xlsx
awesome-claude-skillsgithub.com/awesome-claude/skills产品经理类、写作类技能
everything-claude-skillsgithub.com/everything-claude/skills多功能通用技能包

建议:优先从官方仓库安装核心技能,再根据项目需求从社区仓库补充。

API 速览

本节梳理生成界面过程中涉及的核心 API 与交互接口。

浏览器本地存储 API

API方法签名说明
localStorage.setItemsetItem(key: string, value: string): void存储键值对数据
localStorage.getItem`getItem(key: string): stringnull`
localStorage.removeItemremoveItem(key: string): void删除指定键的数据
localStorage.clearclear(): void清空所有本地数据

代码示例

// 存储数据(需序列化为 JSON 字符串)
interface UserData {
  id: string;
  name: string;
  balance: number;
}

const saveUserData = (data: UserData[]): void => {
  localStorage.setItem('users', JSON.stringify(data));
};

// 读取数据
const loadUserData = (): UserData[] => {
  const raw = localStorage.getItem('users');
  if (!raw) return [];
  try {
    return JSON.parse(raw) as UserData[];
  } catch {
    return [];
  }
};

// 删除指定用户
const deleteUser = (id: string): void => {
  const users = loadUserData();
  const filtered = users.filter(u => u.id !== id);
  saveUserData(filtered);
};

迭代修复接口

通过自然语言指令驱动 AI 进行代码修复:

指令类型示例说明
问题定位“请检查账户页面底部出现的乱码问题”AI 定位问题代码位置
代码修复“请修复该乱码问题,并检查其他页面是否有同类问题”AI 自动修改代码并验证
功能优化“请优化删除按钮的交互反馈”AI 调整交互逻辑或样式

修复流程

代码文件 AI 助手 开发者 代码文件 AI 助手 开发者 描述问题(如"账户页面有乱码") 搜索相关代码位置 定位到问题代码行 确认修复 修改代码 修复完成,建议刷新预览 验证通过/继续优化

Demo 示例

完整 HTML 页面示例

以下为 AI 生成的完整 HTML 页面核心结构,可直接运行:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>账户管理系统</title>
  <style>
    /* ===== 全局重置与基础样式 ===== */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      background: linear-gradient(135deg, #fdf2f8 0%, #fce7f3 100%);
      min-height: 100vh;
      padding: 20px;
    }

    /* ===== 布局容器 ===== */
    .container {
      max-width: 1200px;
      margin: 0 auto;
      background: rgba(255, 255, 255, 0.9);
      backdrop-filter: blur(10px);
      border-radius: 24px;
      padding: 30px;
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.08);
    }

    /* ===== 导航栏 ===== */
    .nav {
      display: flex;
      gap: 30px;
      border-bottom: 2px solid #f3e8ff;
      padding-bottom: 16px;
      margin-bottom: 30px;
    }

    .nav a {
      text-decoration: none;
      color: #7c3aed;
      font-weight: 500;
      padding: 8px 16px;
      border-radius: 12px;
      transition: background 0.2s;
    }

    .nav a:hover {
      background: #f3e8ff;
    }

    .nav a.active {
      background: #7c3aed;
      color: #fff;
    }

    /* ===== 页面容器 ===== */
    .page {
      display: none;
    }

    .page.active {
      display: block;
    }

    /* ===== 卡片网格 ===== */
    .stats-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 20px;
      margin-bottom: 30px;
    }

    .stat-card {
      background: #fff;
      padding: 20px;
      border-radius: 16px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
      text-align: center;
    }

    .stat-card h3 {
      color: #6b7280;
      font-size: 14px;
      margin-bottom: 8px;
    }

    .stat-card .number {
      font-size: 32px;
      font-weight: 700;
      color: #1f2937;
    }

    /* ===== 表单 ===== */
    .form-group {
      margin-bottom: 16px;
    }

    .form-group label {
      display: block;
      font-weight: 500;
      margin-bottom: 4px;
      color: #374151;
    }

    .form-group input {
      width: 100%;
      padding: 10px 14px;
      border: 2px solid #e5e7eb;
      border-radius: 12px;
      font-size: 16px;
      transition: border-color 0.2s;
    }

    .form-group input:focus {
      outline: none;
      border-color: #7c3aed;
    }

    .btn {
      padding: 10px 24px;
      border: none;
      border-radius: 12px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.2s;
    }

    .btn-primary {
      background: #7c3aed;
      color: #fff;
    }

    .btn-primary:hover {
      background: #6d28d9;
      transform: translateY(-2px);
    }

    .btn-danger {
      background: #ef4444;
      color: #fff;
    }

    .btn-danger:hover {
      background: #dc2626;
    }

    /* ===== 表格/列表 ===== */
    .user-list {
      list-style: none;
      margin-top: 20px;
    }

    .user-list li {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 16px;
      background: #f9fafb;
      border-radius: 12px;
      margin-bottom: 8px;
    }

    .user-list li .info {
      display: flex;
      gap: 20px;
      align-items: center;
    }

    .user-list li .info .name {
      font-weight: 600;
    }

    .user-list li .info .balance {
      color: #6b7280;
    }
  </style>
</head>
<body>

<div class="container">
  <!-- ===== 导航 ===== -->
  <nav class="nav">
    <a href="#" class="active" data-page="home">首页</a>
    <a href="#" data-page="stats">统计</a>
    <a href="#" data-page="account">账户</a>
  </nav>

  <!-- ===== 首页 ===== -->
  <div id="home" class="page active">
    <h2>👋 欢迎回来</h2>
    <p style="color: #6b7280; margin-top: 8px;">管理您的账户与资产</p>
    <div class="stats-grid">
      <div class="stat-card">
        <h3>总账户数</h3>
        <div class="number" id="totalUsers">0</div>
      </div>
      <div class="stat-card">
        <h3>总资产</h3>
        <div class="number" id="totalBalance">0</div>
      </div>
    </div>
  </div>

  <!-- ===== 统计页 ===== -->
  <div id="stats" class="page">
    <h2>📊 数据统计</h2>
    <div class="stats-grid">
      <div class="stat-card">
        <h3>活跃账户</h3>
        <div class="number" id="activeUsers">0</div>
      </div>
      <div class="stat-card">
        <h3>平均余额</h3>
        <div class="number" id="avgBalance">0</div>
      </div>
    </div>
  </div>

  <!-- ===== 账户页 ===== -->
  <div id="account" class="page">
    <h2>👤 我的账户</h2>

    <!-- 新增表单 -->
    <div style="background: #f9fafb; padding: 20px; border-radius: 16px; margin: 16px 0;">
      <h4>添加账户</h4>
      <div class="form-group">
        <label>姓名</label>
        <input type="text" id="userName" placeholder="请输入姓名">
      </div>
      <div class="form-group">
        <label>余额</label>
        <input type="number" id="userBalance" placeholder="请输入金额">
      </div>
      <button class="btn btn-primary" onclick="addUser()">保存</button>
    </div>

    <!-- 账户列表 -->
    <ul class="user-list" id="userList">
      <!-- 动态渲染 -->
    </ul>
  </div>
</div>

<script>
  // ============================================================
  // 1. 数据层:localStorage 读写
  // ============================================================

  /** 获取所有用户数据 */
  function getUsers() {
    try {
      return JSON.parse(localStorage.getItem('users')) || [];
    } catch {
      return [];
    }
  }

  /** 保存用户数据 */
  function saveUsers(users) {
    localStorage.setItem('users', JSON.stringify(users));
  }

  // ============================================================
  // 2. 页面导航切换
  // ============================================================

  document.querySelectorAll('.nav a').forEach(link => {
    link.addEventListener('click', function(e) {
      e.preventDefault();

      // 导航高亮
      document.querySelectorAll('.nav a').forEach(a => a.classList.remove('active'));
      this.classList.add('active');

      // 页面切换
      const pageId = this.dataset.page;
      document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
      document.getElementById(pageId).classList.add('active');

      // 刷新统计数据
      updateStats();
      renderUsers();
    });
  });

  // ============================================================
  // 3. 核心业务逻辑
  // ============================================================

  /** 添加用户 */
  function addUser() {
    const nameInput = document.getElementById('userName');
    const balanceInput = document.getElementById('userBalance');

    const name = nameInput.value.trim();
    const balance = parseFloat(balanceInput.value);

    if (!name) {
      alert('请输入姓名');
      return;
    }
    if (isNaN(balance) || balance < 0) {
      alert('请输入有效的金额');
      return;
    }

    const users = getUsers();
    const newUser = {
      id: Date.now().toString(),
      name: name,
      balance: balance
    };
    users.push(newUser);
    saveUsers(users);

    // 清空表单
    nameInput.value = '';
    balanceInput.value = '';

    // 刷新界面
    renderUsers();
    updateStats();
  }

  /** 删除用户 */
  function deleteUser(id) {
    if (!confirm('确认删除该账户吗?')) return;
    let users = getUsers();
    users = users.filter(u => u.id !== id);
    saveUsers(users);
    renderUsers();
    updateStats();
  }

  /** 渲染用户列表 */
  function renderUsers() {
    const list = document.getElementById('userList');
    const users = getUsers();

    if (users.length === 0) {
      list.innerHTML = '<li style="text-align:center;color:#9ca3af;">暂无账户数据</li>';
      return;
    }

    list.innerHTML = users.map(u => `
      <li>
        <div class="info">
          <span class="name">${escapeHtml(u.name)}</span>
          <span class="balance">💰 ${u.balance.toFixed(2)}</span>
        </div>
        <button class="btn btn-danger" onclick="deleteUser('${u.id}')">删除</button>
      </li>
    `).join('');
  }

  /** 更新统计数据 */
  function updateStats() {
    const users = getUsers();
    const total = users.length;
    const totalBal = users.reduce((sum, u) => sum + u.balance, 0);

    document.getElementById('totalUsers').textContent = total;
    document.getElementById('totalBalance').textContent = totalBal.toFixed(2);
    document.getElementById('activeUsers').textContent = total;
    document.getElementById('avgBalance').textContent = total > 0 ? (totalBal / total).toFixed(2) : '0.00';
  }

  // ============================================================
  // 4. 工具函数
  // ============================================================

  /** 简单的防 XSS 转义 */
  function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
  }

  // ============================================================
  // 5. 初始化
  // ============================================================

  // 首次加载渲染
  renderUsers();
  updateStats();
</script>

</body>
</html>

运行说明

  1. 将上述完整 HTML 代码保存为 index.html 文件。
  2. 使用任意现代浏览器(Chrome / Edge / Firefox 等)直接双击打开该文件。
  3. 页面将自动初始化,所有数据存储在浏览器本地 localStorage 中。
  4. 切换顶部导航查看不同功能页面:
    • 首页:展示总账户数与总资产概览。
    • 统计:展示活跃账户数与平均余额。
    • 账户:支持新增账户(姓名 + 余额)与删除账户操作。

技术点总结

  • 纯前端实现:无需任何构建工具、包管理器或后端服务,开箱即用。
  • 数据持久化:利用 localStorage API 实现浏览器端数据存储,刷新页面数据不丢失。
  • 响应式 UI:采用 CSS Grid 与 Flexbox 布局,适配不同屏幕尺寸。
  • 事件驱动:页面导航、数据增删均通过事件监听驱动视图更新。
  • 代码组织:数据层、业务逻辑层、渲染层分离,便于后续扩展与维护。

参考文档

官方文档

参考链接

总结

本文系统阐述了在缺乏美术设计资源的情况下,如何利用 AnthropicSkills 机制,从 PRD 文档出发自动化生成具备完整功能与基础视觉风格的 UI 界面。

通过安装 artdesign 等美术设计类 Skills,AI 助手能够模拟从需求分析到界面实现的全流程,显著降低个人开发者与小团队的产品落地门槛。

同时,本文提供了 Skills 的两种安装方式、完整可运行的 HTML 代码示例以及核心 API 说明,验证了该技术路径的可行性与实用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值