React + TypeScript + Vite 实战:从零构建 Color Picker 应用

🎨 React + TypeScript + Vite 实战:从零构建 Color Picker 应用 --- 完整学习日志

阅读时间 :约 15 分钟 | 难度 :入门 ~ 进阶 | 技术栈:React 19 · TypeScript 6 · Vite 8


📖 前言

最近在学习 React + TypeScript 的工程化开发,于是动手实践了一个小项目 ------ Color Picker(颜色选择器)。这个项目虽然不大,但五脏俱全,涵盖了现代 React 开发的诸多核心概念:

  • ✅ TypeScript 类型系统与接口设计
  • ✅ 组件化开发与 Props 通信
  • useState 状态管理与不可变更新
  • useEffect 副作用与异步数据获取
  • ✅ CSS 变量 + 暗黑模式适配
  • ✅ Vite 构建工具链配置
  • ✅ 项目目录结构规范(model / api / components)

本文将 逐文件、逐行 地拆解整个项目,力求让每一位读者都能"看得懂、学得会、用得上"。废话不多说,我们开始!


🏗️ 一、项目架构总览

csharp 复制代码
color-picker/
├── index.html                 # 入口 HTML
├── package.json               # 依赖与脚本
├── vite.config.ts             # Vite 构建配置
├── tsconfig.json              # TypeScript 配置入口
├── tsconfig.app.json          # 应用 TS 配置
├── tsconfig.node.json         # Node 端 TS 配置
├── eslint.config.js           # ESLint 代码规范
├── public/
│   ├── favicon.svg            # 网站图标
│   └── icons.svg              # SVG 图标集
└── src/
    ├── main.tsx               # React 应用挂载入口
    ├── App.tsx                # 根组件
    ├── App.css                # 根组件样式
    ├── index.css              # 全局样式 + CSS 变量
    ├── model/
    │   ├── color.ts           # Color 数据模型
    │   └── member.ts          # MemberEntity 数据模型
    ├── api/
    │   └── memberApi.ts       # 模拟 API 接口
    └── components/
        ├── ColorBrowser.tsx   # 颜色预览组件
        ├── ColorPicker.tsx    # 颜色选择器组件
        └── MemberTable.tsx    # 成员列表组件

🎯 核心设计思想 :按职责分层 ------ model 定义数据形状,api 封装数据获取,components 负责 UI 渲染。这种"数据-逻辑-视图"三层分离的架构,是中大型项目的标配。


⚙️ 二、工程化配置解读

2.1 package.json ------ 项目的"身份证"

json 复制代码
{
  "name": "color-picker",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.6",
    "react-dom": "^19.2.6"
  },
  "devDependencies": {
    "@eslint/js": "^10.0.1",
    "@types/node": "^24.12.3",
    "@types/react": "^19.2.14",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^6.0.1",
    "eslint": "^10.3.0",
    "eslint-plugin-react-hooks": "^7.1.1",
    "eslint-plugin-react-refresh": "^0.5.2",
    "globals": "^17.6.0",
    "typescript": "~6.0.2",
    "typescript-eslint": "^8.59.2",
    "vite": "^8.0.12"
  }
}
🔍 关键知识点解读:
字段 说明
"type": "module" 启用 ES Module 规范,允许使用 import/export 语法,告别 require()
"private": true 防止意外发布到 npm 仓库
"dev": "vite" 启动 Vite 开发服务器,享受毫秒级热更新(HMR)
"build": "tsc -b && vite build" 先 TypeScript 类型检查,再 Vite 打包。注意顺序:类型检查失败则不会打包,保证产物类型安全
react: ^19.2.6 本项目使用的是 React 19!带来了更强的服务端组件、更好的 Suspense 等特性
typescript: ~6.0.2 TypeScript 6.0!这是最新主版本,~ 表示只接受补丁更新

📌 学习要点dependencies vs devDependencies 的区别 ------ 前者是运行时需要的包(react、react-dom),后者是开发/构建时需要的包(TypeScript、Vite、ESLint),不会被打包进最终产物。

2.2 vite.config.ts ------ 构建利器

ts 复制代码
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
})

极其简洁!这得益于 Vite 的"约定优于配置"理念:

  • @vitejs/plugin-react:提供 React Fast Refresh(热更新时不丢失组件状态)、JSX 编译等能力
  • defineConfig:提供完整的 TypeScript 类型提示,写配置时 IDE 会自动补全

2.3 tsconfig.json ------ TypeScript 编译配置

主配置文件通过 Project References 拆分为两个子配置:

json 复制代码
{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

tsconfig.app.json 中值得关注的关键配置:

配置项 含义
target es2023 编译目标为 ES2023,现代浏览器已全面支持
module esnext 使用最新的 ES Module 标准
jsx react-jsx 使用 React 17+ 的自动 JSX 运行时 ,无需手动 import React
moduleResolution bundler 专为打包器(Vite/webpack)设计的模块解析策略
verbatimModuleSyntax true 强制使用 import type 导入纯类型,确保类型导入在编译后被完全擦除
noUnusedLocals true 未使用的局部变量报错 ------ 保持代码干净
noUnusedParameters true 未使用的参数报错 ------ 同上
erasableSyntaxOnly true TS 6.0 新特性 :只允许使用可被擦除的语法(如 enum 不可用,推荐用 const 对象替代)

💡 "jsx": "react-jsx" 这个配置非常实用。在 React 17 之前,每个 .tsx 文件顶部都需要 import React from 'react',有了它之后,编译器会自动注入 JSX 运行时的导入,代码更简洁!


🧱 三、数据模型层(Model)

好的架构从数据建模开始。本项目定义了两个核心模型:

3.1 Color 模型

typescript 复制代码
// src/model/color.ts
export interface Color {
  red: number;
  green: number;
  blue: number;
}

极简却精妙:

  • 使用 RGB 色彩空间 ,每个通道 0~255,与 CSS rgb() 函数天然对应
  • interface(而非 type)更利于后续扩展(可以声明合并)
  • 三个字段精确描述一种颜色,无冗余、无歧义

3.2 MemberEntity 模型

typescript 复制代码
// src/model/member.ts
export interface MemberEntity {
  id: number;
  login: string;
  avatar_url: string;
}

模拟的是 GitHub 用户数据:

  • id:用户唯一标识(数字类型,注意 GitHub API 返回的 id 是 number
  • login:GitHub 用户名
  • avatar_url:头像链接

🎓 最佳实践 :Model 文件只定义类型,不包含任何逻辑。这是"单一职责原则(SRP)"在类型系统上的体现。当项目扩展到几十上百个接口时,你会发现这种分离带来的可维护性优势。


🌐 四、API 层 ------ 模拟异步数据获取

typescript 复制代码
// src/api/memberApi.ts
import type { MemberEntity } from '../model/member';

export const getMembersCollection = (): Promise<MemberEntity[]> => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        {
          id: 1457912,
          login: "brauliodiez",
          avatar_url: "https://avatars.githubusercontent.com/u/1457912?v=3"
        },
        {
          id: 4374977,
          login: "Nasdan",
          avatar_url: "https://avatars.githubusercontent.com/u/4374977?v=3"
        }
      ])
    }, 500);
  })
}
🔍 设计精要:
技巧 说明
import type 纯类型导入,编译后完全消失,对运行时零影响
Promise<MemberEntity[]> 返回值类型明确,调用方知道会拿到什么
setTimeout 500ms 模拟网络延迟,让 UI 有 loading 感知
返回完整数据 模拟真实 API 的返回形状,方便后期替换为真实 fetch 调用

📌 替换为真实 API 只需改一行 :将 getMembersCollection 内部改为 return fetch('https://api.github.com/orgs/lemoncode/members').then(res => res.json()),其余代码完全不变 ------ 这就是接口抽象的魅力!


🧩 五、组件层 ------ 逐行拆解

5.1 入口文件 main.tsx

tsx 复制代码
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)
🔑 关键点:
  1. createRoot(React 18+ API) :取代旧版的 ReactDOM.render,是 Concurrent Mode(并发模式) 的入口
  2. ! 非空断言document.getElementById('root')! 告诉 TypeScript "这个元素一定存在",避免返回 HTMLElement | null 的类型守卫
  3. <StrictMode> :开发环境下的严格模式,会故意双重调用某些生命周期方法,帮助你发现副作用问题
  4. ./index.css :全局样式的导入,Vite 会将其注入到 <head>

5.2 根组件 App.tsx ------ 状态管理的核心

tsx 复制代码
import { useState } from 'react'
import ColorBrowser from './components/ColorBrowser';
import ColorPicker from './components/ColorPicker';
import type { Color } from './model/color';
import MemberTable from './components/MemberTable';

function App() {
  const [color, setColor] = useState<Color>({
    red: 20,
    green: 0,
    blue: 10,
  })

  return (
    <>
      <ColorBrowser color={color} />
      <ColorPicker color={color} onColorUpdated={setColor} />
      <MemberTable />
    </>
  )
}

export default App
🧠 深入理解:

状态提升(Lifting State Up)

scss 复制代码
App (状态持有者)
 ├── ColorBrowser  ← 接收 color,只读展示
 ├── ColorPicker   ← 接收 color + onColorUpdated,读写
 └── MemberTable   ← 独立管理自己的状态
  • color 状态定义在 App单一数据源 ),确保 ColorBrowserColorPicker 看到的是同一份颜色数据
  • ColorPicker 通过 onColorUpdated={setColor} 回调通知父组件更新状态 ------ 这是 React 单向数据流的经典实现

泛型 useState<Color> :TypeScript 自动推断出 color 的类型为 ColorsetColor 的参数类型也被约束为 Color。如果你尝试 setColor({ red: "hello" }),编辑器会立刻报错!


5.3 ColorBrowser 组件 ------ 颜色预览

tsx 复制代码
import * as React from 'react';
import type { Color } from '../model/color';

interface Props {
  color: Color;
}

const ColorBrowser: React.FC<Props> = (props) => {
  const divStyle: React.CSSProperties = {
    width: '11rem',
    height: '7rem',
    backgroundColor: `rgb(${props.color.red}, ${props.color.green}, ${props.color.blue})`,
  }
  return (
    <div style={divStyle}></div>
  )
}

export default ColorBrowser;
📝 知识点解析:
技术点 详解
React.FC<Props> 函数组件类型标注,FC = FunctionComponent,自动包含 children 属性
React.CSSProperties CSS 属性的 TypeScript 类型,写错属性名 IDE 会报错
模板字符串拼接 rgb(${r}, ${g}, ${b}) 动态生成 CSS 颜色值
纯展示组件 无自身状态,无副作用 ------ 纯函数式组件的典范

🎨 React.CSSProperties 是项目中最容易被忽视却非常实用的类型。它能防止你写出 backgrounColor(拼写错误)这样的 bug,因为 TypeScript 会立刻提醒!


5.4 ColorPicker 组件 ------ 滑块交互

tsx 复制代码
import * as React from 'react';
import type { Color } from '../model/color';

interface Props {
  color: Color;
  onColorUpdated: (color: Color) => void;
}

const ColorPicker: React.FC<Props> = (props) => {
  return (
    <div>
      <input
        type="range"
        min={0}
        max={255}
        value={props.color.red}
        onChange={(e) =>
          props.onColorUpdated({ ...props.color, red: +e.target.value })
        }
      />
      {props.color.red}
      <br />
      <input
        type="range"
        min={0}
        max={255}
        value={props.color.green}
        onChange={(e) =>
          props.onColorUpdated({ ...props.color, green: +e.target.value })
        }
      />
      {props.color.green}
      <br />
      <input
        type="range"
        min={0}
        max={255}
        value={props.color.blue}
        onChange={(e) =>
          props.onColorUpdated({ ...props.color, blue: +e.target.value })
        }
      />
      {props.color.blue}
    </div>
  )
}

export default ColorPicker;
🧬 核心技巧剖析:

1. 不可变更新(Immutable Update)

typescript 复制代码
{ ...props.color, red: +e.target.value }
//  ↑                ↑
//  展开旧对象        覆盖 red 字段,创建一个全新对象

这是 React 状态更新的黄金法则 ------ 永远不要直接修改原对象 !React 通过 Object.is() 对比新旧状态来决定是否重新渲染。如果你直接 props.color.red = 100,React 无法检测到变化。

2. +e.target.value 的一元加号技巧

typescript 复制代码
e.target.value     // "128" --- 字符串类型
+e.target.value    // 128  --- 数字类型(number)

<input>value 始终是 string,但 Color 接口要求 number+ 运算符是一种简洁的类型转换方式,等价于 Number(e.target.value)

3. <input type="range"> 滑块控件

原生 HTML5 的滑块输入:

属性 含义
min={0} 最小值 0
max={255} 最大值 255(RGB 单通道上限)
value={...} 受控组件的当前值
onChange={...} 滑块拖动时的回调

5.5 MemberTable 组件 ------ 异步数据 + 列表渲染

tsx 复制代码
import * as React from 'react';
import { getMembersCollection } from '../api/memberApi';
import type { MemberEntity } from '../model/member';

const MemberRow = (props) => {
  const member = props.member
  return (
    <tr>
      <td>
        <img src={member.avatar_url} style={{ maxWidth: '10rem' }} />
      </td>
      <td><span>{member.id}</span></td>
      <td><span>{member.login}</span></td>
    </tr>
  )
}

const MemberTable: React.FC = () => {
  const [memberCollection, setMemberCollection] = React.useState<MemberEntity[]>([]);

  React.useEffect(() => {
    (async () => {
      const members = await getMembersCollection();
      setMemberCollection(members);
    })()
  }, []);

  return (
    <>
      <table>
        <thead>
          <tr>
            <th>Avatar</th>
            <th>Id</th>
            <th>Name</th>
          </tr>
        </thead>
        <tbody>
          {
            memberCollection.map((member: MemberEntity) => (
              <MemberRow key={member.id} member={member} />
            ))
          }
        </tbody>
      </table>
    </>
  )
}

export default MemberTable;
🔬 深度剖析:

1. useEffect + IIFE(立即执行的异步函数表达式)

typescript 复制代码
React.useEffect(() => {
  (async () => {
    const members = await getMembersCollection();
    setMemberCollection(members);
  })()
}, []);

这个模式非常经典!原因在于:

  • useEffect 的回调不能直接是 async 函数(因为 async 函数返回 Promise,而 useEffect 期望返回 void 或 cleanup 函数)
  • 解决之道:在回调内部定义一个 async 的 IIFE(Immediately Invoked Function Expression),立即调用它

2. 空依赖数组 [] 的含义

表示 "只在组件首次挂载 时执行一次"。相当于类组件中的 componentDidMount

⚠️ 这意味着如果 API 数据更新了,组件不会 自动重新获取。对于真实场景,可能需要加入 [refreshFlag] 依赖或使用 React Query 等方案。

3. key 属性的重要性

tsx 复制代码
memberCollection.map((member) => (
  <MemberRow key={member.id} member={member} />
))

key 是 React 列表渲染的唯一标识符,用于:

  • 追踪列表中的每个元素
  • 优化 diff 算法,避免不必要的 DOM 操作
  • 永远不要用数组索引 index 作为 key(除非列表是静态的、不会增删改的)

4. 子组件 MemberRow 的分离

<tr> 抽成独立组件 MemberRow,遵循单一职责原则。当行逻辑变复杂(如点击事件、条件样式)时,修改不会影响表格整体结构。


🎨 六、样式系统设计

6.1 CSS 变量 + 暗黑模式

css 复制代码
:root {
  --text: #6b6375;
  --text-h: #08060d;
  --bg: #fff;
  --border: #e5e4e7;
  --accent: #aa3bff;
  --accent-bg: rgba(170, 59, 255, 0.1);
  --accent-border: rgba(170, 59, 255, 0.5);
  font: 18px/145% var(--sans);
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

@media (prefers-color-scheme: dark) {
  :root {
    --text: #9ca3af;
    --text-h: #f3f4f6;
    --bg: #16171d;
    --border: #2e303a;
    --accent: #c084fc;
    --accent-bg: rgba(192, 132, 252, 0.15);
    --accent-border: rgba(192, 132, 252, 0.5);
  }
}
✨ 设计亮点:
技巧 说明
CSS 自定义属性(变量) 定义全局设计令牌(Design Tokens),统一管理颜色、间距、字体
prefers-color-scheme: dark 系统级暗黑模式媒体查询,自动适配用户系统偏好
font-synthesis: none 禁止浏览器合成加粗/倾斜字体,避免字体失真
text-rendering: optimizeLegibility 优化文本渲染清晰度(移动端建议换成 optimizeSpeed
-webkit-font-smoothing: antialiased macOS/iOS 字体抗锯齿,渲染更细腻

🎯 核心思想 :CSS 变量本质是"一处修改,全局生效"。如果要换主题色,只需改 --accent 一个变量,所有依赖它的组件样式自动更新。

6.2 CSS 嵌套语法

css 复制代码
#next-steps ul {
  list-style: none;
  padding: 0;
  display: flex;
  gap: 8px;
  margin: 32px 0 0;

  .logo {
    height: 18px;
  }

  a {
    color: var(--text-h);
    font-size: 16px;
    /* ... */

    &:hover {
      box-shadow: var(--shadow);
    }
  }

  @media (max-width: 1024px) {
    margin-top: 20px;
    flex-wrap: wrap;
    justify-content: center;
  }
}

项目使用了 CSS 原生嵌套(CSS Nesting) 语法,这是现代 CSS 的重大升级:

  • .logo 嵌套在 ul 内,编译为 #next-steps ul .logo
  • &:hover 引用父选择器,编译为 #next-steps ul a:hover
  • @media 写在选择器内部,作用域更清晰

📌 目前 CSS 嵌套在 Vite 中开箱即用,无需 Sass/Less 预处理器。

6.3 CSS Modules 替代方案?

本项目使用全局 CSS 方式组织样式。在大型项目中,更推荐使用 CSS Modules.module.css)或 CSS-in-JS 方案(如 Tailwind CSS、styled-components)来避免样式冲突。不过对于学习项目,全局 CSS 更直观,理解成本更低。


🔄 七、数据流全景图

scss 复制代码
┌──────────────────────────────────────────────────┐
│                     App (状态中心)                  │
│                                                    │
│  const [color, setColor] = useState<Color>({       │
│    red: 20, green: 0, blue: 10                     │
│  })                                                │
│                                                    │
│  ┌─────────────────┐  ┌─────────────────────┐     │
│  │  ColorBrowser    │  │    ColorPicker       │     │
│  │                  │  │                      │     │
│  │  color → 显示    │  │  color → range 值    │     │
│  │  RGB 色块        │  │  onChange → setColor │     │
│  │  (只读, 纯展示)   │  │  (读写, 修改状态)    │     │
│  └─────────────────┘  └─────────────────────┘     │
│                                                    │
│  ┌─────────────────────────────────────────────┐  │
│  │               MemberTable                     │  │
│  │                                               │  │
│  │  useState<MemberEntity[]>  (独立状态)         │  │
│  │  useEffect → getMembersCollection()           │  │
│  │  .map() → <MemberRow />                       │  │
│  └─────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘
🔑 关键原则总结:
  1. 单向数据流:数据从父组件流向子组件(通过 Props),子组件通过回调函数通知父组件更新
  2. 状态提升:共享状态放在最近的公共祖先组件中
  3. 组件自治MemberTable 的状态是私有的,与 color 状态互不干扰

📊 八、技术要点速查表

技术点 具体实现 所在文件
TypeScript 接口 interface Color { red, green, blue } model/color.ts
类型导入 import type { Color } from '...' 多个文件
泛型 useState useState<Color>({...}) App.tsx
Props 类型标注 React.FC<Props> + interface Props 各组件
CSS 对象类型 React.CSSProperties ColorBrowser.tsx
不可变更新 { ...obj, field: newVal } ColorPicker.tsx
字符串转数字 +e.target.value ColorPicker.tsx
useEffect + async IIFE 模式 (async () => {...})() MemberTable.tsx
受控组件 <input value={...} onChange={...} /> ColorPicker.tsx
列表 key <MemberRow key={member.id} /> MemberTable.tsx
CSS 变量 --accent, --bg, --border index.css
暗黑模式 prefers-color-scheme: dark index.css
CSS 嵌套 &:hover, & > div App.css

🧪 九、运行与验证

bash 复制代码
# 1. 进入项目目录
cd color-picker

# 2. 安装依赖
npm install

# 3. 启动开发服务器
npm run dev
# → Vite 启动在 http://localhost:5173

# 4. 生产构建
npm run build
# → 先 tsc 类型检查,再 vite 打包到 dist/

# 5. 预览生产构建
npm run preview

# 6. 代码质量检查
npm run lint

💡 十、学习心得与最佳实践

✅ 做得好的地方

  1. 类型系统充分利用 :每个 Props 都有明确的 interface 定义,函数返回值都有类型标注,让代码即文档
  2. 组件职责清晰:展示(ColorBrowser)、交互(ColorPicker)、数据(MemberTable)三类组件各司其职
  3. API 层抽象:mock 数据和真实 API 共用相同的接口签名,随时可以切换
  4. 现代化工具链:Vite 8 + React 19 + TypeScript 6,全部是最新版本

🔧 可以改进的地方

改进方向 具体方案
Loading 状态 MemberTable 在数据加载完成前展示骨架屏或 Spinner
Error 状态 API 请求失败时的错误处理和重试机制
CSS Modules 将全局 CSS 迁移为 .module.css,避免样式冲突
使用 React 19 新特性 尝试 use() Hook、useOptimistic 等新 API
自定义 Hook MemberTable 中的 useEffect + useState 抽取为 useMembers() Hook
单元测试 为组件和 API 添加 Vitest + React Testing Library 测试
a11y 无障碍 为滑块添加 aria-label,为颜色块添加合适的语义标签

📚 延伸学习路径

vbnet 复制代码
本项目的知识点 → 下一步学习方向
────────────────────────────────────
TypeScript 接口  → 泛型、工具类型(Partial/Pick/Omit)、条件类型
React 状态管理   → useReducer、Context API、Zustand、Redux Toolkit
组件通信         → Context、Event Bus、状态管理库
CSS 方案         → CSS Modules、Tailwind CSS、styled-components
异步数据         → React Query (TanStack Query)、SWR、RTK Query
构建工具         → Vite 插件开发、esbuild、Rolldown
测试             → Vitest、React Testing Library、Playwright

🎯 十一、总结

这个 Color Picker 项目虽然代码量不大(约 150 行核心代码),但它完整地展示了一个现代 React + TypeScript 项目的标准开发范式:

  1. 类型先行 ------ 先定义数据模型,再写组件
  2. 状态驱动 ------ UI 是状态的函数,state → render
  3. 单向数据流 ------ Props 向下,回调向上
  4. 关注点分离 ------ Model / API / Components 分层清晰
  5. 工程化完备 ------ Vite 构建 + TypeScript 类型检查 + ESLint 代码规范

🧩 代码虽小,架构不小。 理解了这个项目的每一行代码和背后的设计思想,你就掌握了 React 日常开发的 80% 核心技能。剩下的 20%,是在真实项目中不断打磨的工程经验。


相关推荐
谁在黄金彼岸1 小时前
Nuxt.js 详解(一):Vue 开发者为什么要关注 Nuxt
前端
英勇无比的消炎药1 小时前
TinyRobot v0.5.0 深度解读(三):Layout 组件——如何组织复杂工作区的页面布局
前端·vue.js
默_笙1 小时前
😋 我让 DeepSeek-R1 在浏览器本地跑了起来,后端同事说"你认真的?"
前端·javascript
英勇无比的消炎药1 小时前
TinyRobot v0.5.0 深度解读(四):CLI 脚手架——从零搭建 AI 应用的工程化实践
前端·vue.js·github
程序员黑豆2 小时前
鸿蒙应用开发之双向绑定实战:从 V1 到 V2 的完整迁移指南
前端·harmonyos
Escape2 小时前
为什么你的 AI 越聊越傻?从 Token 到 Agent,彻底搞懂 AI Agent的秘密㊙️
前端·人工智能·后端
李明卫杭州2 小时前
Vue3 响应式概念 ↔ React 对应方案(类组件与函数组件)对照笔记
前端·vue.js·react.js
windliang2 小时前
Claude Code 源码分析(二):CC 的心脏 queryLoop Agent主循环
前端·ai编程·claude
Revolution613 小时前
reactive 对象重新赋值后,表单为什么没有恢复默认值
前端·vue.js·面试