普通视图

发现新文章,点击刷新页面。
昨天以前首页

CSS选择器完全手册:精准控制网页样式的艺术

作者 Dream耀
2025年6月5日 23:08

CSS选择器完全指南:从基础到高级应用

CSS选择器是前端开发中最基础也是最重要的概念之一,它决定了样式规则将应用于哪些HTML元素。本文将全面介绍CSS选择器的各种类型和使用方法,帮助您掌握精确控制页面样式的技巧。

一、CSS基础概念回顾

在深入探讨选择器之前,让我们先回顾几个CSS基础概念:

  1. 声明(Declaration) :一个属性与值的键值对,如color: red;
  2. 声明块(Declaration Block) :由大括号{}包围的一组声明
  3. 选择器(Selector) :指定样式规则将应用于哪些HTML元素
  4. 规则集(Ruleset) :选择器加上声明块的完整组合

css

/* 这是一个完整的规则集 */
h1 {
  color: blue;      /* 声明 */
  font-size: 24px;  /* 声明 */
}

二、基本选择器类型

2.1 元素选择器(类型选择器)

元素选择器直接使用HTML标签名来选择元素,是最简单的选择器类型。

css

/* 选择所有<p>元素 */
p {
  color: #333;
}

/* 选择所有<h1>元素 */
h1 {
  font-size: 2em;
}

2.2 类选择器

类选择器以点号(.)开头,选择具有特定class属性的元素。

html

<p class="warning">这是一条警告信息</p>

css

.warning {
  color: red;
  font-weight: bold;
}

一个元素可以有多个类,类名用空格分隔:

html

<p class="warning urgent">紧急警告!</p>

2.3 ID选择器

ID选择器以井号(#)开头,选择具有特定id属性的元素。ID在文档中应该是唯一的。

html

<div id="header">网站标题</div>

css

#header {
  background-color: #f0f0f0;
  padding: 20px;
}

2.4 通配选择器

通配选择器(*)匹配任何元素,常用于重置样式。

css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

三、组合选择器

组合选择器可以将多个简单选择器组合在一起,实现更精确的选择。

3.1 后代选择器(空格)

选择某个元素内部的所有特定后代元素,不论嵌套层级。

css

/* 选择<div>内所有的<p> */
div p {
  line-height: 1.6;
}

3.2 子元素选择器(>)

只选择直接子元素,不选择更深层级的后代。

css

/* 只选择<ul>的直接<li>子元素 */
ul > li {
  list-style-type: square;
}

3.3 相邻兄弟选择器(+)

选择紧接在另一个元素后的兄弟元素,且二者有相同的父元素。

css

/* 选择紧跟在<h1>后的<p> */
h1 + p {
  margin-top: 0;
}

3.4 通用兄弟选择器(~)

选择某个元素之后的所有同级元素。

css

/* 选择<h1>之后的所有<p>兄弟元素 */
h1 ~ p {
  color: #666;
}

四、属性选择器

属性选择器根据元素的属性及属性值来选择元素。

4.1 基本属性选择器

css

/* 选择有title属性的元素 */
[title] {
  border-bottom: 1px dotted #999;
}

/* 选择type属性值为"text"的<input>元素 */
input[type="text"] {
  border: 1px solid #ccc;
}

4.2 属性值匹配选择器

css

/* 选择href属性以"https"开头的<a>元素 */
a[href^="https"] {
  color: green;
}

/* 选择src属性以".png"结尾的<img>元素 */
img[src$=".png"] {
  border: 2px solid blue;
}

/* 选择class属性包含"logo"的元素 */
[class*="logo"] {
  opacity: 0.8;
}

五、伪类选择器

伪类选择器用于定义元素的特殊状态。

5.1 链接相关伪类

css

/* 未访问的链接 */
a:link {
  color: blue;
}

/* 已访问的链接 */
a:visited {
  color: purple;
}

/* 鼠标悬停状态 */
a:hover {
  color: red;
  text-decoration: underline;
}

/* 激活状态(鼠标按下未释放) */
a:active {
  color: green;
}

5.2 表单相关伪类

css

/* 获得焦点的输入框 */
input:focus {
  outline: 2px solid orange;
}

/* 被禁用的表单元素 */
input:disabled {
  background-color: #eee;
}

/* 被选中的复选框或单选按钮 */
input:checked {
  border-color: blue;
}

5.3 结构伪类

css

/* 选择第一个子元素 */
li:first-child {
  font-weight: bold;
}

/* 选择最后一个子元素 */
li:last-child {
  border-bottom: none;
}

/* 选择第3个子元素 */
li:nth-child(3) {
  color: red;
}

/* 选择奇数子元素 */
tr:nth-child(odd) {
  background-color: #f9f9f9;
}

/* 选择偶数子元素 */
tr:nth-child(even) {
  background-color: #fff;
}

/* 选择唯一的子元素 */
div:only-child {
  margin: 0 auto;
}

六、伪元素选择器

伪元素选择器用于选择元素的特定部分而不是元素本身。

6.1 ::before和::after

css

/* 在每个<p>前插入内容 */
p::before {
  content: "→ ";
  color: green;
}

/* 在每个<p>后插入内容 */
p::after {
  content: " ←";
  color: green;
}

6.2 ::first-letter和::first-line

css

/* 选择第一个字母 */
p::first-letter {
  font-size: 2em;
  float: left;
}

/* 选择第一行 */
p::first-line {
  font-weight: bold;
}

6.3 ::selection

css

/* 选择用户选中的文本 */
::selection {
  background-color: yellow;
  color: black;
}

七、选择器优先级与特异性

当多个选择器应用于同一个元素时,CSS有一套优先级规则决定哪个样式生效。

7.1 特异性计算规则

特异性由四个部分组成:[内联样式, ID选择器, 类/属性/伪类选择器, 元素/伪元素选择器]

  • 内联样式:1,0,0,0
  • ID选择器:0,1,0,0
  • 类/属性/伪类选择器:0,0,1,0
  • 元素/伪元素选择器:0,0,0,1

7.2 优先级示例

css

*               /* 0,0,0,0 - 最低 */
li              /* 0,0,0,1 */
ul li           /* 0,0,0,2 */
ul ol+li        /* 0,0,0,3 */
h1 + [rel=up]   /* 0,0,1,1 */
ul ol li.red    /* 0,0,1,3 */
li.red.level    /* 0,0,2,1 */
#header         /* 0,1,0,0 */
style=""        /* 1,0,0,0 - 最高 */

7.3 !important规则

!important可以覆盖所有其他规则,但应谨慎使用。

css

p {
  color: red !important;
}

八、实用选择器技巧

8.1 组合使用选择器

css

/* 选择class为"btn"且disabled的按钮 */
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* 选择表格中除了第一行外的所有奇数行 */
tr:not(:first-child):nth-child(odd) {
  background-color: #f5f5f5;
}

8.2 选择空元素

css

/* 选择内容为空的<div> */
div:empty {
  display: none;
}

8.3 选择特定语言的元素

html

<p lang="en">Hello!</p>
<p lang="fr">Bonjour!</p>

css

/* 选择法语内容 */
p:lang(fr) {
  font-style: italic;
}

九、现代CSS选择器新特性

9.1 :is()和:where()伪类

css

/* 传统写法 */
header h1, 
header h2, 
header h3 {
  margin-bottom: 0;
}

/* 使用:is()简化 */
header :is(h1, h2, h3) {
  margin-bottom: 0;
}

/* :where()特异性总是0 */
:where(header) h1 {
  margin-bottom: 0;  /* 特异性=0,0,0,1 */
}

9.2 :has()伪类(父选择器)

css

/* 选择包含<img>的<a> */
a:has(img) {
  border: 1px solid #ccc;
}

/* 选择包含至少一个<li>的<ul> */
ul:has(> li) {
  padding-left: 20px;
}

9.3 焦点相关伪类

css

/* 任何获得焦点的元素 */
:focus {
  outline: 2px solid blue;
}

/* 当浏览器认为元素应该显示焦点状态时 */
:focus-visible {
  outline: 2px dashed green;
}

/* 当元素及其后代获得焦点时 */
:focus-within {
  background-color: #f0f8ff;
}

十、选择器最佳实践

  1. 保持简洁:避免过于复杂的选择器
  2. 避免过度使用ID选择器:特异性太高难以覆盖
  3. 合理使用类选择器:可复用性高
  4. 注意性能:浏览器从右向左解析选择器
  5. 使用有意义的命名:如.btn-primary而非.blue-btn

css

/* 不推荐 - 过于具体 */
div#main-content ul.nav li a.active {
  color: red;
}

/* 推荐 - 更简洁 */
.nav-link.active {
  color: red;
}

结语

CSS选择器是前端开发中的强大工具,掌握各种选择器的使用方法可以让你更精确地控制页面样式。从简单的基础选择器到复杂的组合选择器,再到现代的伪类选择器,合理运用这些工具可以大幅提高你的开发效率和样式控制能力。

记住,好的CSS不仅仅是让页面看起来漂亮,还要考虑可维护性、性能和可访问性。选择器的合理使用是实现这些目标的关键之一。

智能前端的 Fetch 革命:解锁 Web 与 AI 的无缝交互

作者 Dream耀
2025年6月5日 22:55

使用 Fetch API 实现现代前端数据交互

引言

在当今的 Web 开发中,前端与后端的数据交互是构建动态应用的核心。传统的页面刷新方式已经无法满足用户对流畅体验的需求,而 Fetch API 的出现为 JavaScript 带来了全新的生命力。本文将深入探讨 Fetch API 的工作原理、使用方法以及如何利用它与大模型服务(如 DeepSeek)进行交互。

一、Fetch API 概述

Fetch API 是现代浏览器提供的一个用于发起网络请求的接口,它比传统的 XMLHttpRequest 更加强大、灵活且易于使用。Fetch 基于 Promise 设计,使得异步请求的处理更加优雅。

1.1 Fetch 的基本语法

javascript

fetch(url, options)
  .then(response => {
    // 处理响应
  })
  .catch(error => {
    // 处理错误
  });

或者使用 async/await 语法:

javascript

async function fetchData() {
  try {
    const response = await fetch(url, options);
    const data = await response.json();
    // 处理数据
  } catch (error) {
    // 处理错误
  }
}

1.2 Fetch 与传统 AJAX 的比较

特性 Fetch API XMLHttpRequest
语法 基于 Promise,更简洁 回调函数,较复杂
请求/响应对象 标准化 非标准化
默认携带 Cookie 不携带 携带
超时控制 需要额外实现 原生支持
取消请求 使用 AbortController 原生支持
进度事件 有限支持 完整支持

二、Fetch API 的详细使用

2.1 发起 GET 请求

GET 请求是最常见的请求类型,用于从服务器获取数据:

javascript

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    console.log('Success:', data);
    // 更新DOM
    document.getElementById('content').innerHTML = 
      data.map(item => `<li>${item.name}</li>`).join('');
  })
  .catch(error => {
    console.error('Error:', error);
  });

2.2 发起 POST 请求

POST 请求用于向服务器发送数据,如提交表单或调用 API:

javascript

const userData = {
  username: 'example',
  email: 'example@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your_token_here'
  },
  body: JSON.stringify(userData)
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));

2.3 处理不同的响应类型

Fetch API 可以处理多种响应格式:

javascript

// 处理JSON响应
fetch('/api/data.json')
  .then(response => response.json())
  .then(data => console.log(data));

// 处理文本响应
fetch('/api/data.txt')
  .then(response => response.text())
  .then(text => console.log(text));

// 处理Blob响应(如图片)
fetch('/image.png')
  .then(response => response.blob())
  .then(blob => {
    const objectURL = URL.createObjectURL(blob);
    document.getElementById('image').src = objectURL;
  });

2.4 错误处理

正确的错误处理对于健壮的应用至关重要:

javascript

async function fetchWithErrorHandling() {
  try {
    const response = await fetch('https://api.example.com/data');
    
    if (!response.ok) {
      // 根据HTTP状态码抛出不同的错误
      if (response.status === 404) {
        throw new Error('Resource not found');
      } else if (response.status === 401) {
        throw new Error('Unauthorized');
      } else {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
    }
    
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Fetch error:', error);
    // 显示用户友好的错误信息
    displayErrorMessage(error.message);
  }
}

function displayErrorMessage(message) {
  const errorElement = document.getElementById('error-message');
  errorElement.textContent = message;
  errorElement.style.display = 'block';
}

三、高级 Fetch 用法

3.1 设置请求超时

Fetch API 本身不支持超时设置,但可以通过 AbortController 实现:

javascript

const controller = new AbortController();
const signal = controller.signal;

// 设置5秒超时
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://api.example.com/data', { signal })
  .then(response => response.json())
  .then(data => {
    clearTimeout(timeoutId);
    console.log(data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Request timed out');
    } else {
      console.error('Other error:', error);
    }
  });

3.2 上传文件

使用 Fetch 上传文件:

javascript

const formData = new FormData();
const fileInput = document.querySelector('input[type="file"]');

formData.append('file', fileInput.files[0]);
formData.append('username', 'exampleUser');

fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData
  // 注意:不要手动设置Content-Type头,浏览器会自动设置正确的boundary
})
.then(response => response.json())
.then(data => console.log('Upload success:', data))
.catch(error => console.error('Upload error:', error));

3.3 请求取消

使用 AbortController 取消正在进行的请求:

javascript

const controller = new AbortController();

// 开始请求
fetch('https://api.example.com/data', {
  signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
  if (error.name === 'AbortError') {
    console.log('Request was aborted');
  } else {
    console.error('Error:', error);
  }
});

// 在某个事件中取消请求
document.getElementById('cancel-button').addEventListener('click', () => {
  controller.abort();
});

3.4 并发请求

使用 Promise.all 处理多个并发请求:

javascript

async function fetchMultipleResources() {
  try {
    const [usersResponse, postsResponse] = await Promise.all([
      fetch('https://api.example.com/users'),
      fetch('https://api.example.com/posts')
    ]);
    
    if (!usersResponse.ok || !postsResponse.ok) {
      throw new Error('One or more requests failed');
    }
    
    const users = await usersResponse.json();
    const posts = await postsResponse.json();
    
    console.log('Users:', users);
    console.log('Posts:', posts);
    
    // 合并数据并更新UI
    displayCombinedData(users, posts);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

function displayCombinedData(users, posts) {
  // 实现数据合并和显示逻辑
}

四、Fetch 与大模型服务的集成

4.1 调用 DeepSeek 等大模型 API

现代前端可以直接调用大模型服务的 API,实现智能功能:

javascript

async function queryDeepSeek(prompt) {
  const apiKey = 'your_api_key_here'; // 实际应用中应从安全的地方获取
  
  try {
    const response = await fetch('https://api.deepseek.com/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`
      },
      body: JSON.stringify({
        model: 'deepseek-chat',
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.7,
        max_tokens: 1000
      })
    });
    
    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.error?.message || 'API request failed');
    }
    
    const data = await response.json();
    return data.choices[0].message.content;
  } catch (error) {
    console.error('API call failed:', error);
    throw error;
  }
}

// 使用示例
document.getElementById('ask-button').addEventListener('click', async () => {
  const question = document.getElementById('question-input').value;
  const answerElement = document.getElementById('answer');
  
  answerElement.textContent = '思考中...';
  
  try {
    const answer = await queryDeepSeek(question);
    answerElement.textContent = answer;
  } catch (error) {
    answerElement.textContent = `出错: ${error.message}`;
  }
});

4.2 流式处理大模型响应

对于长文本生成,可以使用流式处理来改善用户体验:

javascript

async function streamDeepSeekResponse(prompt) {
  const apiKey = 'your_api_key_here';
  const response = await fetch('https://api.deepseek.com/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: 'deepseek-chat',
      messages: [{ role: 'user', content: prompt }],
      temperature: 0.7,
      max_tokens: 1000,
      stream: true // 启用流式响应
    })
  });
  
  if (!response.ok) {
    throw new Error(`API request failed with status ${response.status}`);
  }
  
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let result = '';
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    const chunk = decoder.decode(value, { stream: true });
    const lines = chunk.split('\n').filter(line => line.trim() !== '');
    
    for (const line of lines) {
      const message = line.replace(/^data: /, '');
      if (message === '[DONE]') {
        return result;
      }
      
      try {
        const parsed = JSON.parse(message);
        const content = parsed.choices[0]?.delta?.content || '';
        result += content;
        document.getElementById('stream-output').textContent += content;
      } catch (error) {
        console.error('Error parsing message:', error);
      }
    }
  }
  
  return result;
}

4.3 前端缓存策略

为了提高性能并减少 API 调用,可以实现简单的前端缓存:

javascript

const apiCache = new Map();

async function cachedFetch(url, options = {}) {
  const cacheKey = `${url}:${JSON.stringify(options)}`;
  
  // 检查缓存
  if (apiCache.has(cacheKey)) {
    const { data, timestamp } = apiCache.get(cacheKey);
    // 5分钟缓存有效期
    if (Date.now() - timestamp < 5 * 60 * 1000) {
      return data;
    }
  }
  
  // 发起新请求
  const response = await fetch(url, options);
  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }
  
  const data = await response.json();
  
  // 更新缓存
  apiCache.set(cacheKey, {
    data,
    timestamp: Date.now()
  });
  
  return data;
}

// 使用示例
document.getElementById('load-data').addEventListener('click', async () => {
  try {
    const data = await cachedFetch('https://api.example.com/data');
    displayData(data);
  } catch (error) {
    console.error('Error:', error);
  }
});

五、Fetch 在实际应用中的最佳实践

5.1 封装通用请求函数

在实际项目中,建议封装一个通用的请求函数:

javascript

class ApiClient {
  constructor(baseUrl, defaultHeaders = {}) {
    this.baseUrl = baseUrl;
    this.defaultHeaders = {
      'Content-Type': 'application/json',
      ...defaultHeaders
    };
  }
  
  async request(endpoint, method = 'GET', body = null, customHeaders = {}) {
    const url = `${this.baseUrl}${endpoint}`;
    const headers = { ...this.defaultHeaders, ...customHeaders };
    
    const config = {
      method,
      headers,
      credentials: 'include' // 如果需要发送cookie
    };
    
    if (body) {
      config.body = typeof body === 'object' ? JSON.stringify(body) : body;
    }
    
    try {
      const response = await fetch(url, config);
      
      if (!response.ok) {
        const errorData = await this.parseResponse(response);
        throw new HttpError(response.status, errorData.message || 'Request failed');
      }
      
      return await this.parseResponse(response);
    } catch (error) {
      console.error(`API request failed: ${error.message}`);
      throw error;
    }
  }
  
  async parseResponse(response) {
    const contentType = response.headers.get('content-type');
    if (contentType && contentType.includes('application/json')) {
      return await response.json();
    }
    return await response.text();
  }
  
  get(endpoint, headers) {
    return this.request(endpoint, 'GET', null, headers);
  }
  
  post(endpoint, body, headers) {
    return this.request(endpoint, 'POST', body, headers);
  }
  
  put(endpoint, body, headers) {
    return this.request(endpoint, 'PUT', body, headers);
  }
  
  delete(endpoint, headers) {
    return this.request(endpoint, 'DELETE', null, headers);
  }
}

class HttpError extends Error {
  constructor(status, message) {
    super(message);
    this.status = status;
    this.name = 'HttpError';
  }
}

// 使用示例
const api = new ApiClient('https://api.example.com', {
  'Authorization': 'Bearer your_token_here'
});

async function loadUserData(userId) {
  try {
    const user = await api.get(`/users/${userId}`);
    const posts = await api.get(`/users/${userId}/posts`);
    return { user, posts };
  } catch (error) {
    if (error.status === 404) {
      console.log('User not found');
    } else {
      console.error('Error loading user data:', error);
    }
    throw error;
  }
}

5.2 处理身份验证

对于需要身份验证的 API,可以这样处理:

javascript

let authToken = null;

async function login(username, password) {
  try {
    const response = await fetch('/api/auth/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ username, password })
    });
    
    if (!response.ok) {
      throw new Error('Login failed');
    }
    
    const data = await response.json();
    authToken = data.token;
    localStorage.setItem('authToken', data.token);
    return data.user;
  } catch (error) {
    console.error('Login error:', error);
    throw error;
  }
}

async function fetchWithAuth(url, options = {}) {
  if (!authToken) {
    authToken = localStorage.getItem('authToken');
    if (!authToken) {
      throw new Error('Not authenticated');
    }
  }
  
  const headers = {
    ...options.headers,
    'Authorization': `Bearer ${authToken}`
  };
  
  return fetch(url, { ...options, headers });
}

// 使用示例
async function loadProtectedData() {
  try {
    const response = await fetchWithAuth('/api/protected/data');
    const data = await response.json();
    console.log('Protected data:', data);
    return data;
  } catch (error) {
    console.error('Error loading protected data:', error);
    if (error.message === 'Not authenticated') {
      // 重定向到登录页面
      window.location.href = '/login';
    }
    throw error;
  }
}

5.3 性能优化技巧

  1. 批量请求:合并多个小请求为一个批量请求
  2. 请求去重:避免同时发送相同的请求
  3. 请求优先级:关键请求优先发送
  4. 预加载:预测用户行为提前加载数据

javascript

class RequestScheduler {
  constructor(maxConcurrent = 5) {
    this.maxConcurrent = maxConcurrent;
    this.queue = [];
    this.activeCount = 0;
  }
  
  enqueue(requestFn, priority = 0) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject, priority });
      this.queue.sort((a, b) => b.priority - a.priority);
      this.processQueue();
    });
  }
  
  async processQueue() {
    if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) {
      return;
    }
    
    this.activeCount++;
    const { requestFn, resolve, reject } = this.queue.shift();
    
    try {
      const result = await requestFn();
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.activeCount--;
      this.processQueue();
    }
  }
}

// 使用示例
const scheduler = new RequestScheduler(3);

async function fetchWithPriority(url, priority = 0) {
  return scheduler.enqueue(() => fetch(url).then(r => r.json()), priority);
}

// 高优先级请求
fetchWithPriority('/api/critical-data', 10)
  .then(data => console.log('Critical data:', data));

// 普通优先级请求
fetchWithPriority('/api/normal-data')
  .then(data => console.log('Normal data:', data));

六、Fetch 的现代替代方案

虽然 Fetch API 功能强大,但在某些场景下可以考虑以下替代方案:

6.1 Axios

Axios 是一个流行的 HTTP 客户端库,提供了一些额外功能:

javascript

import axios from 'axios';

// 简单GET请求
axios.get('/api/data')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

// 带配置的POST请求
axios.post('/api/users', {
  name: 'John Doe',
  email: 'john@example.com'
}, {
  headers: {
    'Authorization': 'Bearer token'
  },
  timeout: 5000
})
.then(response => console.log(response.data));

6.2 React Query (TanStack Query)

对于 React 应用,React Query 提供了强大的数据获取和缓存功能:

javascript

import { useQuery } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const { data, error, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => 
      fetch(`/api/users/${userId}`)
        .then(res => res.json()),
    staleTime: 5 * 60 * 1000 // 5分钟缓存
  });
  
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div>
      <h1>{data.name}</h1>
      <p>Email: {data.email}</p>
    </div>
  );
}

6.3 SWR (Stale-While-Revalidate)

另一个 React 数据获取库,由 Vercel 开发:

javascript

import useSWR from 'swr';

const fetcher = (...args) => fetch(...args).then(res => res.json());

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher, {
    refreshInterval: 30000 // 每30秒刷新
  });
  
  if (error) return <div>Failed to load</div>;
  if (!data) return <div>Loading...</div>;
  
  return <div>Hello {data.name}!</div>;
}

七、未来展望:Fetch 与 AI 时代的结合

随着大模型技术的发展,前端与 AI 的交互变得越来越普遍。Fetch API 将成为连接前端与大模型服务的重要桥梁:

  1. 实时 AI 交互:通过流式 Fetch 实现与大模型的实时对话
  2. 边缘计算:将部分 AI 推理工作下放到边缘节点,减少延迟
  3. 个性化体验:根据用户行为数据实时调整 AI 响应
  4. 混合架构:结合本地小型模型和云端大模型,平衡性能与效果

javascript

// 未来可能的AI增强Fetch示例
async function aiEnhancedFetch(resource, init) {
  // 分析请求上下文
  const context = analyzeRequestContext(resource, init);
  
  // 根据上下文决定是否使用本地模型
  if (shouldUseLocalModel(context)) {
    const localResult = await runLocalAI(init.body);
    return new Response(JSON.stringify(localResult));
  }
  
  // 否则调用云端大模型
  const response = await fetch(resource, init);
  
  // 后处理:可能缓存结果或生成摘要
  return postProcessResponse(response);
}

结语

Fetch API 是现代 Web 开发的基石之一,它简化了前端与后端的通信,为构建动态、响应式的 Web 应用提供了强大支持。随着 AI 技术的普及,Fetch 将成为连接前端智能与云端大模型的关键技术。掌握 Fetch 的高级用法和最佳实践,将帮助开发者构建更高效、更智能的 Web 应用。

无论是传统的 REST API 交互,还是新兴的大模型服务调用,Fetch API 都将继续发挥重要作用。希望本文能够帮助读者深入理解 Fetch 的工作原理,并在实际项目中灵活运用这些技术。

❌
❌