Skip to content

框架与库

简介

前端框架与库是现代Web开发的基石,它们提供了结构化的开发范式、可复用的组件和优化的性能,使开发者能够更高效地构建复杂的Web应用。从简单的工具库到全功能框架,不同的解决方案适合不同的项目需求。

本节内容涵盖主流前端框架、状态管理库、UI组件库及其生态系统,帮助开发者选择和掌握适合的技术栈。

技术领域

前端框架

  • React生态系统
    • React核心概念
    • React Server Components
    • React并发模式
    • React性能优化
  • Vue生态系统
    • Vue 3组合式API
    • 响应式系统
    • 单文件组件
    • Vue性能优化
  • Angular生态系统
    • 依赖注入
    • RxJS与Observable
    • Angular表单
    • Angular Universal
  • 轻量级框架
    • Svelte编译时优化
    • Solid细粒度响应性
    • Lit元素与Web组件
    • Qwik即时水合技术

全栈框架

  • Next.js
    • App Router与Pages Router
    • 服务器组件与客户端组件
    • 数据获取策略
    • 静态生成与服务端渲染
    • 中间件与Edge功能
  • Nuxt.js
    • Nuxt 3架构
    • 自动路由与布局系统
    • 服务器API与中间件
    • 组合式API与模块化
    • SEO与性能优化
  • Remix
    • 嵌套路由
    • 加载器与动作
    • 错误边界
    • 缓存控制
  • Astro
    • 岛屿架构
    • 内容集合
    • 零JS默认
    • 混合渲染策略

状态管理

  • 集中式状态管理
    • Redux与Redux Toolkit
    • Vuex与Pinia
    • MobX与MobX-State-Tree
    • Zustand与Jotai
  • 服务器状态管理
    • React Query/TanStack Query
    • SWR数据获取
    • Apollo Client
    • RTK Query

组件库与设计系统

  • 通用组件库
    • MUI (Material-UI)
    • Ant Design
    • Chakra UI
    • Tailwind组件
  • 专业领域组件
    • 数据可视化库
    • 表格与网格组件
    • 表单解决方案
    • 动画与过渡

路由与导航

  • React Router
  • Vue Router
  • Angular Router
  • 单页应用架构
  • 多页应用架构

代码示例

jsx
// Next.js App Router示例
// app/products/[category]/page.tsx

import { Suspense } from 'react';
import { ProductList } from '@/components/product-list';
import { CategoryHeader } from '@/components/category-header';
import { getProducts, getCategory } from '@/lib/api';

// 生成静态路由参数
export async function generateStaticParams() {
  const categories = await fetch('https://api.example.com/categories').then(res => res.json());
  
  return categories.map((category) => ({
    category: category.slug,
  }));
}

// 生成元数据
export async function generateMetadata({ params }) {
  const category = await getCategory(params.category);
  
  return {
    title: `${category.name} - 我的电商`,
    description: category.description,
    openGraph: {
      images: [{ url: category.image }],
    },
  };
}

// 页面组件
export default async function CategoryPage({ params }) {
  // 直接在服务器获取分类信息
  const category = await getCategory(params.category);
  
  return (
    <main>
      <CategoryHeader 
        title={category.name}
        description={category.description}
        imageUrl={category.image}
      />
      
      <section className="products">
        <h2>产品列表</h2>
        
        <Suspense fallback={<p>加载产品中...</p>}>
          {/* 将加载产品的逻辑封装在组件中,支持流式渲染 */}
          <ProductList categoryId={category.id} />
        </Suspense>
      </section>
    </main>
  );
}

// components/product-list.tsx
export async function ProductList({ categoryId }) {
  // 这部分会在服务器上异步加载,不会阻塞页面其他部分的渲染
  const products = await getProducts(categoryId);
  
  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
      {products.map(product => (
        <div key={product.id} className="product-card">
          <img src={product.image} alt={product.name} />
          <h3>{product.name}</h3>
          <p>{product.price}</p>
          <AddToCartButton product={product} />
        </div>
      ))}
    </div>
  );
}

// 客户端组件
'use client';

import { useState } from 'react';

export function AddToCartButton({ product }) {
  const [isAdding, setIsAdding] = useState(false);
  
  async function handleAddToCart() {
    setIsAdding(true);
    
    try {
      await fetch('/api/cart', {
        method: 'POST',
        body: JSON.stringify({ productId: product.id }),
      });
      // 显示成功提示
    } catch (error) {
      // 显示错误提示
    } finally {
      setIsAdding(false);
    }
  }
  
  return (
    <button 
      onClick={handleAddToCart}
      disabled={isAdding}
      className="btn btn-primary"
    >
      {isAdding ? '添加中...' : '加入购物车'}
    </button>
  );
}
vue
<!-- Nuxt 3组件示例 -->
<!-- pages/products/[id].vue -->
<script setup>
// 从URL参数获取产品ID
const route = useRoute();
const { id } = route.params;

// 使用Nuxt的数据获取composable
const { data: product, pending, error } = await useFetch(`/api/products/${id}`);

// 头部元数据
useHead({
  title: product.value ? `${product.value.name} - 我的商店` : '加载中...',
  meta: [
    { name: 'description', content: product.value?.description || '' }
  ]
});

// 客户端状态
const quantity = ref(1);
const isAddingToCart = ref(false);

// 添加到购物车方法
async function addToCart() {
  if (!product.value) return;
  
  isAddingToCart.value = true;
  
  try {
    await $fetch('/api/cart', {
      method: 'POST',
      body: {
        productId: product.value.id,
        quantity: quantity.value
      }
    });
    
    // 使用Nuxt的toast模块显示成功消息
    useToast().success('已添加到购物车');
  } catch (err) {
    useToast().error('添加失败,请重试');
  } finally {
    isAddingToCart.value = false;
  }
}
</script>

<template>
  <div>
    <!-- 加载状态 -->
    <div v-if="pending" class="loading-skeleton">
      <div class="skeleton-image"></div>
      <div class="skeleton-text"></div>
      <div class="skeleton-text"></div>
    </div>
    
    <!-- 错误状态 -->
    <div v-else-if="error" class="error-container">
      <p>抱歉,无法加载产品信息</p>
      <NuxtLink to="/products">返回产品列表</NuxtLink>
    </div>
    
    <!-- 产品详情 -->
    <div v-else-if="product" class="product-detail">
      <div class="product-gallery">
        <img :src="product.imageUrl" :alt="product.name" class="main-image" />
        <div class="thumbnail-list">
          <img 
            v-for="(img, index) in product.gallery" 
            :key="index" 
            :src="img" 
            :alt="`${product.name} - 图片 ${index + 1}`"
            class="thumbnail"
          />
        </div>
      </div>
      
      <div class="product-info">
        <h1>{{ product.name }}</h1>
        <p class="product-price">{{ formatPrice(product.price) }}</p>
        <div class="product-description" v-html="product.description"></div>
        
        <div class="product-actions">
          <div class="quantity-selector">
            <button @click="quantity = Math.max(1, quantity - 1)">-</button>
            <input type="number" v-model="quantity" min="1" />
            <button @click="quantity++">+</button>
          </div>
          
          <button 
            class="add-to-cart-button"
            :disabled="isAddingToCart"
            @click="addToCart"
          >
            {{ isAddingToCart ? '添加中...' : '加入购物车' }}
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.product-detail {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
}

@media (max-width: 768px) {
  .product-detail {
    grid-template-columns: 1fr;
  }
}

/* 其他样式省略 */
</style>

最佳实践

  • 基于项目需求选择适合的框架
  • 考虑团队熟悉度与学习曲线
  • 状态管理遵循单向数据流
  • 提高组件可复用性
  • 优化渲染性能
  • 逻辑与UI分离

用知识点燃技术的火山