📚 完整教程目录

前言:什么是Web框架?

🤔 Web框架的定义

Web框架是一套预先编写好的代码和工具,用来简化Web应用的开发。它提供了组件化、状态管理、路由等功能。

为什么需要Web框架?

主流Web框架

💡 重点:选择框架时要考虑项目规模、团队经验和生态支持。

框架对比分析

核心特性对比

特性 React Vue Angular
学习难度 中等 简单 困难
性能 优秀 优秀 优秀
生态 最完善 完善 完善
社区 最活跃 活跃 活跃
适用场景 大型应用 中小型应用 企业应用

选择建议

React完全指南

React的核心概念

函数组件和Hooks

import React, { useState, useEffect } from 'react'; // 函数组件 function Counter() { // useState Hook const [count, setCount] = useState(0); const [name, setName] = useState(''); // useEffect Hook useEffect(() => { document.title = `Count: ${count}`; // 清理函数 return () => { document.title = 'React App'; }; }, [count]); // 依赖数组 return ( <div> <h1>Count: {count}</h1> <button onClick={() => setCount(count + 1)}> Increment </button> <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Enter name" /> <p>Hello, {name}</p> </div> ); } export default Counter;

常用Hooks

// useState - 状态 const [count, setCount] = useState(0); // useEffect - 副作用 useEffect(() => { // 组件挂载或依赖变化时执行 return () => { // 清理函数 }; }, [dependencies]); // useContext - 上下文 const theme = useContext(ThemeContext); // useReducer - 复杂状态 const [state, dispatch] = useReducer(reducer, initialState); // useCallback - 缓存函数 const memoizedCallback = useCallback(() => { // 函数体 }, [dependencies]); // useMemo - 缓存值 const memoizedValue = useMemo(() => { return expensiveComputation(a, b); }, [a, b]); // useRef - 引用 const inputRef = useRef(null);

组件通信

// 父组件 function Parent() { const [message, setMessage] = useState(''); return ( <div> <Child message={message} onMessageChange={setMessage} /> </div> ); } // 子组件 function Child({ message, onMessageChange }) { return ( <div> <p>{message}</p> <button onClick={() => onMessageChange('Hello')}> Send Message </button> </div> ); }

条件渲染和列表

function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); const items = ['apple', 'banana', 'orange']; return ( <div> {/* 条件渲染 */} {isLoggedIn ? ( <p>Welcome back!</p> ) : ( <p>Please log in</p> )} {/* 列表渲染 */} <ul> {items.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </div> ); }

Vue完全指南

Vue的核心概念

Vue 3 Composition API

<template> <div> <h1>Count: {{ count }}</h1> <button @click="increment">Increment</button> <input v-model="name" placeholder="Enter name"> <p>Hello, {{ name }}</p> <ul> <li v-for="item in items" :key="item"> {{ item }} </li> </ul> </div> </template> <script setup> import { ref, computed, watch, onMounted } from 'vue'; // 响应式数据 const count = ref(0); const name = ref(''); const items = ref(['apple', 'banana', 'orange']); // 方法 const increment = () => { count.value++; }; // 计算属性 const doubleCount = computed(() => count.value * 2); // 监听器 watch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`); }); // 生命周期 onMounted(() => { console.log('Component mounted'); }); </script> <style scoped> h1 { color: blue; } </style>

组件通信

// 父组件 <template> <Child :message="message" @update-message="message = $event" /> </template> <script setup> import { ref } from 'vue'; import Child from './Child.vue'; const message = ref(''); </script> // 子组件 (Child.vue) <template> <div> <p>{{ message }}</p> <button @click="$emit('update-message', 'Hello')"> Send Message </button> </div> </template> <script setup> defineProps({ message: String }); defineEmits(['update-message']); </script>

条件和列表

<template> <div> <!-- 条件渲染 --> <p v-if="isLoggedIn">Welcome back!</p> <p v-else>Please log in</p> <!-- 列表渲染 --> <ul> <li v-for="item in items" :key="item"> {{ item }} </li> </ul> <!-- 类和样式绑定 --> <div :class="{ active: isActive }"> Dynamic class </div> <div :style="{ color: activeColor }"> Dynamic style </div> </div> </template>

Angular简介

Angular的特点

Angular组件

import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-counter', template: ` <div> <h1>Count: {{ count }}</h1> <button (click)="increment()">Increment</button> <input [(ngModel)]="name" placeholder="Enter name"> <p>Hello, {{ name }}</p> <ul> <li *ngFor="let item of items"> {{ item }} </li> </ul> </div> `, styles: [` h1 { color: blue; } `] }) export class CounterComponent { count = 0; name = ''; items = ['apple', 'banana', 'orange']; @Input() message: string = ''; @Output() messageChange = new EventEmitter<string>(); increment() { this.count++; } sendMessage() { this.messageChange.emit('Hello'); } }

Angular服务和依赖注入

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class UserService { constructor(private http: HttpClient) {} getUsers() { return this.http.get('/api/users'); } createUser(user: any) { return this.http.post('/api/users', user); } } // 在组件中使用 @Component({ selector: 'app-users', template: `...` }) export class UsersComponent { users: any[] = []; constructor(private userService: UserService) {} ngOnInit() { this.userService.getUsers().subscribe( (data) => this.users = data ); } }

状态管理

为什么需要状态管理?

Redux(React)

import { createSlice, configureStore } from '@reduxjs/toolkit'; // 创建slice const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; } } }); // 创建store const store = configureStore({ reducer: { counter: counterSlice.reducer } }); // 在组件中使用 import { useSelector, useDispatch } from 'react-redux'; function Counter() { const count = useSelector(state => state.counter.value); const dispatch = useDispatch(); return ( <div> <p>Count: {count}</p> <button onClick={() => dispatch(counterSlice.actions.increment())}> Increment </button> </div> ); }

Vuex(Vue)

import { createStore } from 'vuex'; const store = createStore({ state() { return { count: 0 }; }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } }, actions: { incrementAsync({ commit }) { setTimeout(() => { commit('increment'); }, 1000); } }, getters: { doubleCount: (state) => state.count * 2 } }); // 在组件中使用 <template> <div> <p>Count: {{ $store.state.count }}</p> <button @click="$store.commit('increment')"> Increment </button> </div> </template>

路由和导航

React Router

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; function App() { return ( <BrowserRouter> <nav> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/users/1">User 1</Link> </nav> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/users/:id" element={<UserDetail />} /> <Route path="*" element={<NotFound />} /> </Routes> </BrowserRouter> ); } // 获取路由参数 import { useParams } from 'react-router-dom'; function UserDetail() { const { id } = useParams(); return <div>User ID: {id}</div>; }

Vue Router

import { createRouter, createWebHistory } from 'vue-router'; const routes = [ { path: '/', component: Home }, { path: '/about', component: About }, { path: '/users/:id', component: UserDetail }, { path: '/:pathMatch(.*)*', component: NotFound } ]; const router = createRouter({ history: createWebHistory(), routes }); // 在模板中使用 <template> <nav> <router-link to="/">Home</router-link> <router-link to="/about">About</router-link> </nav> <router-view /> </template> // 获取路由参数 <script setup> import { useRoute } from 'vue-router'; const route = useRoute(); const userId = route.params.id; </script>

生命周期和Hooks

React Hooks生命周期

import { useState, useEffect } from 'react'; function Component() { const [count, setCount] = useState(0); // 组件挂载和更新时执行 useEffect(() => { console.log('Component mounted or updated'); // 清理函数(组件卸载时执行) return () => { console.log('Component unmounted'); }; }, []); // 空依赖数组 - 仅在挂载时执行 // 监听特定依赖 useEffect(() => { console.log('Count changed:', count); }, [count]); return <div>Count: {count}</div>; }

Vue生命周期

<script setup> import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'; // 挂载前 onBeforeMount(() => { console.log('Before mount'); }); // 挂载后 onMounted(() => { console.log('Mounted'); }); // 更新前 onBeforeUpdate(() => { console.log('Before update'); }); // 更新后 onUpdated(() => { console.log('Updated'); }); // 卸载前 onBeforeUnmount(() => { console.log('Before unmount'); }); // 卸载后 onUnmounted(() => { console.log('Unmounted'); }); </script>

测试和调试

React测试(Jest + React Testing Library)

import { render, screen, fireEvent } from '@testing-library/react'; import Counter from './Counter'; describe('Counter Component', () => { test('renders counter', () => { render(<Counter />); expect(screen.getByText(/Count: 0/i)).toBeInTheDocument(); }); test('increments count', () => { render(<Counter />); const button = screen.getByRole('button', { name: /increment/i }); fireEvent.click(button); expect(screen.getByText(/Count: 1/i)).toBeInTheDocument(); }); });

Vue测试(Vitest + Vue Test Utils)

import { describe, it, expect } from 'vitest'; import { mount } from '@vue/test-utils'; import Counter from './Counter.vue'; describe('Counter Component', () => { it('renders counter', () => { const wrapper = mount(Counter); expect(wrapper.text()).toContain('Count: 0'); }); it('increments count', async () => { const wrapper = mount(Counter); await wrapper.find('button').trigger('click'); expect(wrapper.text()).toContain('Count: 1'); }); });

调试工具

实战项目:构建完整的Web应用

项目需求

项目结构(React)

src/ ├── components/ │ ├── TaskList.jsx │ ├── TaskForm.jsx │ ├── TaskItem.jsx │ └── Auth.jsx ├── pages/ │ ├── Home.jsx │ ├── Login.jsx │ └── NotFound.jsx ├── store/ │ ├── taskSlice.js │ ├── authSlice.js │ └── store.js ├── services/ │ └── api.js ├── App.jsx └── main.jsx

核心实现

// store/taskSlice.js import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; export const fetchTasks = createAsyncThunk( 'tasks/fetchTasks', async () => { const response = await fetch('/api/tasks'); return response.json(); } ); const taskSlice = createSlice({ name: 'tasks', initialState: { items: [], loading: false }, extraReducers: (builder) => { builder .addCase(fetchTasks.pending, (state) => { state.loading = true; }) .addCase(fetchTasks.fulfilled, (state, action) => { state.items = action.payload; state.loading = false; }); } }); // components/TaskList.jsx import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchTasks } from '../store/taskSlice'; function TaskList() { const dispatch = useDispatch(); const { items, loading } = useSelector(state => state.tasks); useEffect(() => { dispatch(fetchTasks()); }, [dispatch]); if (loading) return <div>Loading...</div>; return ( <ul> {items.map(task => ( <li key={task.id}>{task.title}</li> ))} </ul> ); }
✨ 实战总结:

通过这个项目,你学会了如何使用现代Web框架构建完整的应用,包括状态管理、路由、API集成等。

🎉 Web框架学习完成

现在你已经掌握了现代Web框架的核心知识。

✅ 你现在可以:

🚀 下一步学习

  1. 深入学习选定框架的高级特性
  2. 学习服务端渲染(SSR)
  3. 学习静态生成(SSG)
  4. 学习性能优化
  5. 学习全栈开发
💡 建议:

选择一个框架深入学习,而不是浅尝所有框架。实践是最好的老师。