这是一份面向前端初学者的极简通俗指南,旨在帮助你用最短的时间建立起对现代前端开发的全局认知与核心实战能力。

模仿《The Little Go Book》等系列小册子的风格,本小册子不堆砌冗长的 API 文档,而是专注于:厘清核心概念、对比新旧演进、掌握现代 React + TypeScript 实战范式

前端基础

网页的本质是运行在浏览器中的图形界面。现代前端开发虽然框架林立,但其基石始终没有改变。

三剑客的分工:HTML、CSS 与 JavaScript

我们可以把网页比作一个人:

flowchart TD subgraph WebPage["网页 (Web Page)"] HTML["HTML (骨架)
定义网页结构与文本语义"] CSS["CSS (皮肤与样式)
负责视觉美化与排版布局"] JS["JavaScript (灵魂与逻辑)
响应用户交互与处理数据"] end CSS -->|应用样式到| HTML JS -->|操作 DOM 改变| HTML JS -->|动态修改样式| CSS

一个最基础的内联示例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>基础示例</title>

  <!-- 【CSS 部分】:定义样式与排版(皮肤),包裹在 <style> 标签中 -->
  <style>
    /* CSS 控制 HTML 元素的视觉呈现 */
    .btn {
      background-color: #0070f3; /* 背景颜色 */
      color: white;              /* 字体颜色 */
      padding: 8px 16px;         /* 内边距 */
      border: none;              /* 去除默认边框 */
      border-radius: 4px;        /* 圆角 */
      cursor: pointer;           /* 鼠标悬停显示手型光标 */
    }
  </style>
</head>
<body>
  <!-- 【HTML 部分】:定义页面结构与节点内容(骨架) -->
  <!-- <h1> 标签:定义页面标题,id 供 JavaScript 查找 -->
  <h1 id="title">Hello Frontend!</h1>
  <!-- <button> 标签:定义按钮,class 应用上面的 CSS 样式 -->
  <button class="btn" id="myBtn">点击我</button>

  <!-- 【JavaScript 部分】:编写动态逻辑与交互(灵魂),包裹在 <script> 标签中 -->
  <script>
    // JS 逻辑 1:通过 ID 查找获取 HTML 节点对象(DOM 操作)
    const btn = document.getElementById('myBtn');
    const title = document.getElementById('title');
    
    // JS 逻辑 2:为按钮添加点击事件监听器,被点击时修改标题内容
    btn.addEventListener('click', () => {
      title.textContent = '你好,前端世界!';
    });
  </script>
</body>
</html>

C/S 架构与 HTTP 协议

在前端开发中,浏览器是客户端(Client),提供数据与逻辑处理的后端程序是服务端(Server)。两者通过 HTTP 协议 进行通信。

sequenceDiagram autonumber actor User as 用户 / 浏览器 (Client) participant Server as 后端服务器 (Server) participant DB as 数据库 (Database) User->>Server: HTTP 请求 (GET /api/users/1) Note over Server: 路由匹配与业务逻辑处理 Server->>DB: 查询数据库记录 DB-->>Server: 返回查询数据 Server-->>User: HTTP 响应 (200 OK + JSON 数据) Note over User: 浏览器接收并动态渲染页面

前端在 JavaScript 中发起 HTTP 请求的现代标准写法:

// 使用 Fetch API 发起异步 GET 请求
async function fetchUserData() {
  try {
    const response = await fetch('https://api.example.com/users/1');
    if (!response.ok) {
      throw new Error(`HTTP 错误!状态码: ${response.status}`);
    }
    const data = await response.json();
    console.log('获取到的用户数据:', data);
  } catch (error) {
    console.error('请求失败:', error);
  }
}

React 基础语法

为什么需要 React?React 与 HTML/CSS/JS 是什么关系?

许多初学者会困惑:有了 HTML、CSS、JS,为什么还要学 React?React 会替代它们吗?

flowchart LR subgraph Traditional["传统原生开发 (指令式 / 手动拧螺丝)"] direction TB T1["数据改变"] --> T2["手动查找 DOM 节点
getElementById"] T2 --> T3["手动修改 DOM 属性
element.innerText = ..."] T3 --> T4["视图更新"] end subgraph ModernReact["React 模式 (声明式 / 蓝图渲染)"] direction TB R1["数据改变"] --> R2["更新 State 状态"] R2 --> R3["React 自动计算 Diff
UI = f(State)"] R3 --> R4["自动高效更新 DOM"] end

React 引入了声明式 UI思想:$UI = f(state)$。你只需关心数据状态(State),界面的真实更新完全交由 React 自动完成。

核心概念:State(状态)与 Hooks(钩子)

什么是 State(状态)?

State 是组件的“记忆”。

什么是 Hooks(钩子)?

早期的 React 函数组件只是简单的“纯函数”,无法记录数据状态,也无法执行复杂的操作。

React 16.8 引入了 Hooks——它们是一系列以 use 开头的特殊函数,允许函数组件**“钩入”** React 的底层能力(如状态、生命周期、上下文等)。

最核心的两个 Hook:

  1. useState(状态钩子):给组件添加内部状态。

    const [count, setCount] = useState(0);
    // count: 当前状态值
    // setCount: 用来更新状态的函数(调用它会触发界面重新渲染)
    // 0: 状态的初始值
    
  2. useEffect(副作用钩子):处理网络请求、定时器、手动修改 DOM 等“非渲染逻辑”(副作用)。

    useEffect(() => {
      // 在这里执行副作用逻辑(如发起 API 请求)
      console.log('组件渲染了或 count 改变了');
    }, [count]); // 依赖项数组:只有 count 改变时才重新触发
    

Hooks 使用的两大黄金规则

  1. 只在最顶层调用 Hook:不要在循环、条件语句(if)或嵌套函数中调用 Hook,确保每次渲染时 Hook 的调用顺序保持一致。
  2. 只在 React 函数组件中调用 Hook:不要在普通 JavaScript 函数中调用(除非是在自定义 Hook 中)。

JSX 语法

JSX 是怎么来的?

在 React 出现前,在 JavaScript 代码里生成 HTML 极其痛苦。开发者只能写拼接字符串:

// 过去的恶心写法:在 JS 里用字符串拼接 HTML
const htmlStr = '<div class="user-card"><h2>' + name + '</h2></div>';

这种写法既容易漏掉引号,又没有任何语法高亮。

React 团队想:“为什么不能直接在 JavaScript 中像写 HTML 一样写界面呢?

于是 JSX (JavaScript XML) 诞生了!它允许你直接在 JS 里写 HTML 标签。

注意:浏览器本身是不认识 JSX 的!在构建编译阶段,工具(如 Vite / Babel)会自动把 JSX 翻译为纯 JavaScript 代码:

  • <h1>Hello</h1> $\rightarrow$ 会被翻译为 React.createElement('h1', null, 'Hello')

JSX 核心语法规则

function UserCard({ name, isAdmin, tags }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      {isAdmin && <span className="badge">管理员</span>}
      <ul>
        {tags.map((tag, index) => (
          <li key={index}>{tag}</li>
        ))}
      </ul>
    </div>
  );
}

组件写法变迁:Class 组件 (老的写法) vs 函数组件 + Hooks

React 经历了从 Class 组件到函数组件的演进。

老的写法:Class 组件

在 React 16.8 之前,包含状态和生命周期的组件必须使用 Class 继承写法。你可能会在维护老旧项目时遇到它:

import React from 'react';

class CounterClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  componentDidMount() {
    console.log('组件已挂载');
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>当前计数{this.state.count}</p>
        <button onClick={this.increment}> 1</button>
      </div>
    );
  }
}

现代写法:函数组件与 Hooks

现代 React 推荐使用纯函数组件配合 Hooks。最常用的两个 Hook 为:

import React, { useState, useEffect } from 'react';

function CounterFunction() {
  const [count, setCount] = useState(0);

  // 监听 count 变化并更新网页标题(副作用)
  useEffect(() => {
    document.title = `点击了 ${count} 次`;
  }, [count]);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      当前计数{count}
    </button>
  );
}

TypeScript 基础应用

为什么需要 TypeScript?

JavaScript 是一门动态弱类型语言。这意味着:变量的类型可以随时改变,参数传错也不会在写代码时提示报错。

在 React 中定义组件的 Props 和 State 类型:

import React, { useState } from 'react';

// 定义接口 (Interface)
interface TodoItem {
  id: number;
  text: string;
  completed: boolean;
}

interface TodoProps {
  initialTitle: string;
  onAddTodo?: (text: string) => void;
}

export const TodoList: React.FC<TodoProps> = ({ initialTitle, onAddTodo }) => {
  const [todos, setTodos] = useState<TodoItem[]>([]);
  const [inputText, setInputText] = useState<string>('');

  const handleAdd = () => {
    if (!inputText.trim()) return;
    const newTodo: TodoItem = {
      id: Date.now(),
      text: inputText,
      completed: false,
    };
    setTodos([...todos, newTodo]);
    setInputText('');
    onAddTodo?.(inputText);
  };

  return (
    <div>
      <h3>{initialTitle}</h3>
      <input
        type="text"
        value={inputText}
        onChange={(e: React.ChangeEvent<HTMLInputElement>) => setInputText(e.target.value)}
      />
      <button onClick={handleAdd}>添加</button>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
    </div>
  );
};

前端项目规范和示例

推荐的项目目录结构

一个标准且易于扩展的现代 React (Vite / Next.js) 项目架构通常如下:

my-frontend-app/
├── public/              # 静态资源(图片、图标等直接复制的文件)
├── src/
│   ├── assets/          # 打包构建的静态资源
│   ├── components/      # 通用 UI 组件(Button, Modal, Input 等)
│   ├── hooks/           # 自定义 Hooks(如 useAuth, useFetch)
│   ├── pages/           # 页面级组件(Home, Dashboard, Login)
│   ├── services/        # 网络请求与 API 接口定义
│   ├── types/           # 全局 TypeScript 类型定义
│   ├── utils/           # 通用工具函数
│   ├── App.tsx          # 根组件
│   ├── main.tsx         # 应用入口点
│   └── index.css        # 全局样式
├── package.json         # 项目依赖与脚本配置
├── tsconfig.json        # TypeScript 编译配置
└── vite.config.ts       # 构建工具配置

组件划分与编码规范

  1. 单一职责原则:每个组件只做一件事。复杂的页面拆分为子组件。
  2. 命名规范
    • 组件文件名与组件名采用 PascalCase(如 UserCard.tsx)。
    • 工具函数与变量采用 camelCase(如 formatDate.ts)。
  3. 状态下放:只将多个组件共享的状态放到公共父组件或全局 State 中,局部状态留在组件内部。

构建、运行和发布

现代前端工程化依赖于 Node.js 环境与自动化构建工具。

flowchart LR Src["开发源码
(.tsx / .css)"] -->|npm run build| Vite["Vite 打包构建"] Vite -->|编译/压缩/TreeShaking| Dist["dist 目录
(静态 HTML, JS, CSS)"] Dist -->|部署发布| Server["Nginx / Vercel 托管"] Server -->|HTTP 服务| Browser["浏览器加载展示"]

开发环境搭建与包管理器

开启一个 Vite + React + TypeScript 项目:

# 使用 npm 创建 Vite 项目
npm create vite@latest my-app -- --template react-ts

# 进入项目目录并安装依赖
cd my-app
npm install

# 启动本地开发服务器
npm run dev

构建打包(Build)

在开发阶段,开发服务器使用 HMR(模块热替换) 让你在修改代码时实时看到效果。

当开发完成后,需要运行构建命令:

npm run build

构建工具(如 Vite / Webpack)会进行:

  1. TypeScript 类型检查与转译
  2. 代码压缩与混淆(Minification)。
  3. 打包分块与 Tree Shaking(去除未使用的死代码)。
  4. dist/ 目录下生成标准的 HTML、CSS 和 JS 纯静态文件。

发布上线

由于打包生成的是纯静态文件,将其轻松部署至:

Nginx 基础配置示例:

server {
    listen 80;
    server_name example.com;

    location / {
        root /var/www/my-app/dist;
        index index.html;
        # 支持 React Router 等前端单页路由
        try_files $uri $uri/ /index.html;
    }

    # 接口反向代理
    location /api/ {
        proxy_pass http://localhost:8080/;
    }
}

进一步学习

当掌握了基础的开发与构建流程后,建议从以下三个方向深入挖掘:

网络调试 (Network Debugging)

掌握浏览器的 DevTools(开发者工具) 是前端工程必备的基础功:

Node.js 与 V8 引擎

理解 JavaScript 运行时的底层原理能帮助你写出更高性能的代码:

ECMAScript 标准演进

JavaScript 的标准规范称为 ECMAScript。了解现代 ES6+ 特性是编写干净、现代化代码的基础:

参考