当前位置: 首页 > article >正文

React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用

React 实战项目:实时聊天应用

欢迎来到本 React 开发教程专栏 的第 28 篇!在前 27 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和架构模式等核心知识。这一次,我们将通过一个完整的实战项目——实时聊天应用,将这些知识融会贯通,帮助您从理论走向实践。

本项目的目标是为中高级开发者提供一个全面的 React 开发体验。通过这个类似 Slack 的实时聊天应用,您将学习如何分析需求、选择技术栈、实现复杂功能、优化性能并最终部署上线。无论您是希望积累项目经验的中级开发者,还是追求架构优化的高级开发者,这篇文章都将为您提供清晰的指引、丰富的代码示例和深入的场景分析。

引言

实时聊天应用是现代 Web 开发中最具挑战性和实用性的项目之一。它不仅需要处理复杂的用户交互和数据流,还要求高性能和出色的用户体验。在本项目中,我们将构建一个功能完善的聊天应用,支持实时消息传递、用户在线状态显示、消息历史记录、动画效果和状态同步等特性。通过这个项目,您将掌握 React 在实际场景中的高级应用,理解实时通信的实现原理,并学习如何优化和部署一个生产级应用。

这个应用的目标非常明确:为用户提供流畅的聊天体验,同时为开发者提供一个学习和实践 React 高级特性的平台。我们将从需求分析开始,逐步完成技术选型、功能实现、性能优化和上线部署,并在最后提供一个练习,帮助您进一步巩固所学内容。

通过本项目,您将体验到:

  • 需求分析:如何将业务需求转化为技术实现。
  • 技术栈选择:如何根据项目需求选择合适的工具和库。
  • 状态管理:如何使用 React Query 和 Redux Toolkit 管理复杂状态。
  • 实时通信:如何通过 WebSocket 实现消息实时传递。
  • 性能优化:如何通过消息缓存和断线重连提升用户体验。
  • 部署上线:如何将应用部署到 AWS 并确保其稳定运行。

准备好了吗?让我们开始吧!


需求分析

在动手编码之前,我们需要明确项目的功能需求。一个清晰的需求清单不仅能指导开发过程,还能帮助我们理解每个功能的意义。以下是实时聊天应用的核心需求:

  1. 实时消息
    • 用户可以发送和接收消息,消息需实时更新。
    • 支持文本消息和表情输入。
  2. 用户在线状态
    • 显示用户的在线状态(如在线、离线、忙碌)。
    • 支持用户手动设置状态。
  3. 消息历史
    • 用户可以查看历史消息记录。
    • 支持消息搜索和过滤功能。
  4. 动画效果
    • 消息发送和接收时具有动画效果,提升用户体验。
    • 支持消息列表的平滑滚动。
  5. 状态同步
    • 确保不同用户之间的状态同步(如消息已读状态)。
    • 支持多设备登录和状态一致性。

需求背后的意义

这些功能覆盖了实时聊天应用的核心场景,同时为学习 React 提供了丰富的实践机会:

  • 实时消息和在线状态 需要 WebSocket 和实时通信技术的支持。
  • 消息历史和状态同步 涉及数据请求、缓存和一致性管理。
  • 动画效果 展示了如何使用现代库提升用户体验。
  • 多设备支持 引入了状态管理的复杂性,考验架构设计能力。

这些需求还为性能优化(如消息缓存和断线重连)提供了实际场景,确保应用在高负载下依然流畅。


技术栈选择

在实现功能之前,我们需要选择合适的技术栈。以下是本项目使用的工具和技术,以及选择它们的理由:

  • React
    核心前端框架,用于构建用户界面。React 的组件化和声明式编程让开发过程更高效。
  • WebSocket (via Socket.IO)
    用于实现实时通信,确保消息的实时传递。Socket.IO 提供了便捷的 API 和断线重连支持。
  • React Query
    用于管理数据请求和缓存,简化与后端交互并提升性能。
  • Framer Motion
    用于实现动画效果,提升用户体验。其简单而强大的 API 非常适合 React 项目。
  • Redux Toolkit
    用于管理全局状态,确保状态的可预测性和一致性。
  • AWS
    用于部署应用,提供高可用性和可扩展性。

技术栈的优势

  • React:生态丰富,社区活跃,是现代 Web 开发的首选框架。
  • Socket.IO:封装了 WebSocket,简化了实时通信的实现。
  • React Query:自动管理数据获取、缓存和同步,大幅提升开发效率。
  • Framer Motion:提供流畅的动画效果,易于集成到 React 组件中。
  • Redux Toolkit:简化 Redux 的使用,适合复杂状态管理。
  • AWS:支持自动扩展和负载均衡,确保应用的稳定性。

这些工具的组合不仅易于上手,还能帮助您掌握 2025 年 React 开发的最佳实践。


项目实现

现在,我们进入核心部分——代码实现。我们将从项目搭建开始,逐步完成组件设计、WebSocket 集成、状态管理、动画效果和状态同步。

1. 项目搭建

我们使用 Vite 快速创建一个 React 项目,因其构建速度快且配置简单。

npm create vite@latest chat-app -- --template react
cd chat-app
npm install
npm run dev

安装必要的依赖:

npm install react-router-dom @reduxjs/toolkit react-redux @tanstack/react-query framer-motion socket.io-client tailwindcss postcss autoprefixer

初始化 Tailwind CSS:

npx tailwindcss init -p

编辑 tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {content: ["./index.html","./src/**/*.{js,ts,jsx,tsx}",],theme: {extend: {},},plugins: [],
}

src/index.css 中引入 Tailwind:

@tailwind base;
@tailwind components;
@tailwind utilities;

这将启动一个基础项目,接下来我们将实现具体功能。

2. 组件拆分

组件化是 React 的核心思想。通过将应用拆分为小组件,我们提高代码的可读性和复用性。

组件结构
  • App:根组件,负责路由和布局。
  • Header:导航栏,包含用户菜单。
  • ChatList:聊天列表,支持搜索。
  • ChatItem:单个聊天项。
  • ChatWindow:聊天窗口,显示消息和输入框。
  • MessageList:消息列表,支持动画。
  • MessageItem:单个消息。
  • InputBox:消息输入框。
  • UserList:用户列表,显示在线状态。
文件结构
src/
├── components/
│   ├── Header.jsx
│   ├── ChatList.jsx
│   ├── ChatItem.jsx
│   ├── ChatWindow.jsx
│   ├── MessageList.jsx
│   ├── MessageItem.jsx
│   ├── InputBox.jsx
│   └── UserList.jsx
├── features/
│   ├── auth/
│   │   └── authSlice.js
│   ├── chat/
│   │   └── chatSlice.js
│   └── users/
│       └── usersSlice.js
├── pages/
│   ├── Home.jsx
│   ├── Chat.jsx
│   └── Profile.jsx
├── App.jsx
├── main.jsx
└── index.css

3. 路由设计

我们使用 React Router 实现多页面导航。

路由配置
  • /:首页,显示聊天列表。
  • /chat/:id:聊天页面,显示指定聊天。
  • /profile:用户资料页面。

App.jsx

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Header from './components/Header';
import Home from './pages/Home';
import Chat from './pages/Chat';
import Profile from './pages/Profile';function App({ socket }) {return (<Router><div className="min-h-screen bg-gray-100"><Header /><main className="container mx-auto p-4"><Routes><Route path="/" element={<Home socket={socket} />} /><Route path="/chat/:id" element={<Chat socket={socket} />} /><Route path="/profile" element={<Profile />} /></Routes></main></div></Router>);
}export default App;
导航栏

Header.jsx

import { Link } from 'react-router-dom';function Header() {return (<header className="bg-blue-600 text-white p-4 shadow-md"><nav className="flex justify-between items-center max-w-6xl mx-auto"><Link to="/" className="text-xl font-bold">实时聊天</Link><div className="space-x-4"><Link to="/profile" className="hover:underline">个人中心</Link></div></nav></header>);
}export default Header;

4. WebSocket 集成

我们使用 Socket.IO 实现实时通信。

配置 Socket.IO

main.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { io } from 'socket.io-client';
import App from './App';
import store from './store';
import './index.css';const socket = io('http://localhost:3000', { autoConnect: true });ReactDOM.createRoot(document.getElementById('root')).render(<Provider store={store}><App socket={socket} /></Provider>
);
后端示例(Node.js)

为了测试,我们需要一个简单的 Socket.IO 后端(可单独运行):

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');const app = express();
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: '*' } });io.on('connection', (socket) => {console.log('User connected:', socket.id);socket.on('message', (data) => {io.emit('message', { ...data, id: Date.now() });});socket.on('read', (data) => {io.emit('read', data);});socket.on('disconnect', () => {console.log('User disconnected:', socket.id);});
});server.listen(3000, () => {console.log('Server running on port 3000');
});

安装后端依赖并运行:

npm init -y
npm install express socket.io
node server.js
发送和接收消息

ChatWindow.jsx

import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { addMessage } from '../features/chat/chatSlice';
import MessageList from './MessageList';
import InputBox from './InputBox';function ChatWindow({ socket, chatId }) {const dispatch = useDispatch();const [isConnected, setIsConnected] = useState(socket.connected);useEffect(() => {socket.on('connect', () => setIsConnected(true));socket.on('disconnect', () => setIsConnected(false));socket.on('message', (message) => {dispatch(addMessage(message));});socket.emit('read', { chatId });return () => {socket.off('connect');socket.off('disconnect');socket.off('message');};}, [socket, dispatch, chatId]);const sendMessage = (text) => {if (!isConnected) return;socket.emit('message', { text, user: 'Me', chatId });};return (<div className="flex flex-col h-[calc(100vh-80px)] bg-white rounded-lg shadow-lg"><div className="p-4 bg-gray-200"><h2 className="text-lg font-semibold">聊天 #{chatId}</h2><p className="text-sm">{isConnected ? '在线' : '离线'}</p></div><MessageList /><InputBox onSend={sendMessage} disabled={!isConnected} /></div>);
}export default ChatWindow;

5. 状态管理

我们结合 Redux Toolkit 和 React Query 管理应用状态。

配置 Store

store.js

import { configureStore } from '@reduxjs/toolkit';
import authReducer from './features/auth/authSlice';
import chatReducer from './features/chat/chatSlice';
import usersReducer from './features/users/usersSlice';export const store = configureStore({reducer: {auth: authReducer,chat: chatReducer,users: usersReducer,},
});export default store;
聊天状态

features/chat/chatSlice.js

import { createSlice } from '@reduxjs/toolkit';const initialState = {messages: [],
};export const chatSlice = createSlice({name: 'chat',initialState,reducers: {addMessage: (state, action) => {state.messages.push(action.payload);},setMessages: (state, action) => {state.messages = action.payload;},},
});export const { addMessage, setMessages } = chatSlice.actions;
export default chatSlice.reducer;
用户状态

features/users/usersSlice.js

import { createSlice } from '@reduxjs/toolkit';const initialState = {users: [],online: {},
};export const usersSlice = createSlice({name: 'users',initialState,reducers: {setUsers: (state, action) => {state.users = action.payload;},updateOnlineStatus: (state, action) => {state.online = { ...state.online, ...action.payload };},},
});export const { setUsers, updateOnlineStatus } = usersSlice.actions;
export default usersSlice.reducer;
数据缓存

使用 React Query 获取消息历史:

Chat.jsx

import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { useDispatch } from 'react-redux';
import { setMessages } from '../features/chat/chatSlice';
import ChatWindow from '../components/ChatWindow';const fetchMessages = async (chatId) => {const { data } = await axios.get(`/api/chats/${chatId}/messages`);return data;
};function Chat({ socket }) {const dispatch = useDispatch();const chatId = useParams().id;const { data, isLoading } = useQuery({queryKey: ['messages', chatId],queryFn: () => fetchMessages(chatId),onSuccess: (messages) => {dispatch(setMessages(messages));},});if (isLoading) return <div className="text-center">加载中...</div>;return <ChatWindow socket={socket} chatId={chatId} />;
}export default Chat;

6. 动画效果

使用 Framer Motion 为消息添加动画。

MessageItem.jsx

import { motion } from 'framer-motion';function MessageItem({ message }) {return (<motion.divinitial={{ opacity: 0, y: 20 }}animate={{ opacity: 1, y: 0 }}transition={{ duration: 0.3 }}className={`p-3 rounded-lg max-w-xs ${message.user === 'Me' ? 'bg-blue-500 text-white ml-auto' : 'bg-gray-200'}`}><p>{message.text}</p><span className="text-xs opacity-75">{new Date(message.id).toLocaleTimeString()}</span></motion.div>);
}export default MessageItem;

MessageList.jsx

import { useSelector } from 'react-redux';
import { useEffect, useRef } from 'react';
import MessageItem from './MessageItem';function MessageList() {const messages = useSelector((state) => state.chat.messages);const listRef = useRef(null);useEffect(() => {listRef.current?.scrollTo({ top: listRef.current.scrollHeight, behavior: 'smooth' });}, [messages]);return (<div ref={listRef} className="flex-1 overflow-y-auto p-4 space-y-4">{messages.map((msg) => (<MessageItem key={msg.id} message={msg} />))}</div>);
}export default MessageList;

7. 用户界面

聊天列表

ChatList.jsx

import { Link } from 'react-router-dom';function ChatList() {const chats = [{ id: 1, name: '团队讨论' },{ id: 2, name: '技术交流' },];return (<div className="space-y-2">{chats.map((chat) => (<Linkkey={chat.id}to={`/chat/${chat.id}`}className="block p-3 bg-white rounded-lg shadow hover:bg-gray-50">{chat.name}</Link>))}</div>);
}export default ChatList;
输入框

InputBox.jsx

import { useState } from 'react';function InputBox({ onSend, disabled }) {const [text, setText] = useState('');const handleSend = () => {if (!text.trim() || disabled) return;onSend(text);setText('');};return (<div className="p-4 border-t bg-white flex items-center space-x-2"><inputtype="text"value={text}onChange={(e) => setText(e.target.value)}onKeyPress={(e) => e.key === 'Enter' && handleSend()}className="flex-1 p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"placeholder="输入消息..."disabled={disabled}/><buttononClick={handleSend}className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400"disabled={disabled}>发送</button></div>);
}export default InputBox;
用户列表

UserList.jsx

import { useSelector } from 'react-redux';function UserList() {const users = useSelector((state) => state.users.users);const online = useSelector((state) => state.users.online);return (<div className="p-4 bg-white rounded-lg shadow"><h3 className="text-lg font-semibold mb-2">在线用户</h3><ul className="space-y-2">{users.map((user) => (<li key={user.id} className="flex items-center space-x-2"><span className={`w-2 h-2 rounded-full ${online[user.id] ? 'bg-green-500' : 'bg-gray-400'}`}></span><span>{user.name}</span></li>))}</ul></div>);
}export default UserList;

8. 状态同步

已读状态

ChatWindow.jsx 中扩展:

useEffect(() => {socket.on('read', ({ chatId: readChatId }) => {if (readChatId === chatId) {// 更新已读状态}});return () => {socket.off('read');};
}, [socket, chatId]);
在线状态

Home.jsx

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { updateOnlineStatus } from '../features/users/usersSlice';
import ChatList from '../components/ChatList';
import UserList from '../components/UserList';function Home({ socket }) {const dispatch = useDispatch();const users = useSelector((state) => state.users.users);useEffect(() => {socket.on('userStatus', (status) => {dispatch(updateOnlineStatus(status));});// 模拟用户数据dispatch(setUsers([{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }]));return () => {socket.off('userStatus');};}, [socket, dispatch]);return (<div className="grid grid-cols-1 md:grid-cols-3 gap-4"><div className="md:col-span-2"><ChatList /></div><UserList /></div>);
}export default Home;

9. 优化

消息缓存

已通过 React Query 实现,见 Chat.jsx

断线重连

main.jsx 中已启用 autoConnect,但可进一步优化:

socket.on('disconnect', () => {console.log('Disconnected, attempting to reconnect...');
});socket.on('reconnect', () => {console.log('Reconnected successfully');
});
防抖输入

InputBox.jsx

import { useState, useCallback } from 'react';
import debounce from 'lodash/debounce';function InputBox({ onSend, disabled }) {const [text, setText] = useState('');const debouncedSend = useCallback(debounce((value) => onSend(value), 300),[onSend]);const handleSend = () => {if (!text.trim() || disabled) return;debouncedSend(text);setText('');};return (<div className="p-4 border-t bg-white flex items-center space-x-2"><inputtype="text"value={text}onChange={(e) => setText(e.target.value)}onKeyPress={(e) => e.key === 'Enter' && handleSend()}className="flex-1 p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"placeholder="输入消息..."disabled={disabled}/><buttononClick={handleSend}className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400"disabled={disabled}>发送</button></div>);
}export default InputBox;

安装 lodash

npm install lodash

10. 部署

构建项目
npm run build

生成 dist 文件夹。

部署到 AWS
  1. 创建 S3 桶
    在 AWS S3 控制台创建一个桶,上传 dist 文件夹内容,启用静态网站托管。
  2. 配置 CloudFront
    创建 CloudFront 分发,选择 S3 桶,设置默认根对象为 index.html
  3. 域名和 SSL
    配置自定义域名并通过 ACM 添加 SSL 证书。
  4. 访问
    部署完成后,通过 CloudFront 域名访问应用。

后端需部署到 AWS EC2 或 ECS,配置域名和 HTTPS。


练习:添加文件上传功能

为巩固所学,我们设计一个练习:为应用添加文件上传功能。

需求

  • 用户可上传文件并发送到聊天中。
  • 支持图片和视频预览。
  • 在输入框旁添加上传按钮。

实现步骤

  1. 创建 Upload 组件
    components/Upload.jsx 中实现文件选择和上传。
  2. 扩展 WebSocket
    修改后端支持文件数据传输。
  3. 消息预览
    MessageItem 中添加文件类型支持。
  4. 集成到输入框
    InputBox 中添加上传按钮。
示例代码

Upload.jsx

import { useState } from 'react';function Upload({ onUpload }) {const [file, setFile] = useState(null);const handleChange = (e) => {const selectedFile = e.target.files[0];if (selectedFile) setFile(selectedFile);};const handleUpload = () => {if (file) {onUpload(file);setFile(null);}};return (<div className="flex items-center space-x-2"><inputtype="file"onChange={handleChange}className="hidden"id="file-upload"/><labelhtmlFor="file-upload"className="px-3 py-1 bg-gray-200 rounded-lg cursor-pointer hover:bg-gray-300">上传</label>{file && (<buttononClick={handleUpload}className="px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700">发送</button>)}</div>);
}export default Upload;

InputBox.jsx(更新):

import { useState } from 'react';
import Upload from './Upload';function InputBox({ onSend, disabled }) {const [text, setText] = useState('');const handleSend = () => {if (!text.trim() || disabled) return;onSend({ type: 'text', content: text });setText('');};const handleFileUpload = (file) => {const reader = new FileReader();reader.onload = () => {onSend({ type: 'file', content: reader.result, name: file.name });};reader.readAsDataURL(file);};return (<div className="p-4 border-t bg-white flex items-center space-x-2"><inputtype="text"value={text}onChange={(e) => setText(e.target.value)}onKeyPress={(e) => e.key === 'Enter' && handleSend()}className="flex-1 p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"placeholder="输入消息..."disabled={disabled}/><Upload onUpload={handleFileUpload} /><buttononClick={handleSend}className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400"disabled={disabled}>发送</button></div>);
}export default InputBox;

MessageItem.jsx(更新):

import { motion } from 'framer-motion';function MessageItem({ message }) {return (<motion.divinitial={{ opacity: 0, y: 20 }}animate={{ opacity: 1, y: 0 }}transition={{ duration: 0.3 }}className={`p-3 rounded-lg max-w-xs ${message.user === 'Me' ? 'bg-blue-500 text-white ml-auto' : 'bg-gray-200'}`}>{message.type === 'file' ? (message.content.startsWith('data:image') ? (<img src={message.content} alt={message.name} className="max-w-full rounded" />) : message.content.startsWith('data:video') ? (<video controls src={message.content} className="max-w-full rounded" />) : (<a href={message.content} download={message.name} className="underline">{message.name}</a>)) : (<p>{message.content}</p>)}<span className="text-xs opacity-75">{new Date(message.id).toLocaleTimeString()}</span></motion.div>);
}export default MessageItem;
后端更新

server.js

io.on('connection', (socket) => {socket.on('message', (data) => {io.emit('message', { ...data, id: Date.now(), user: socket.id });});
});

练习目标

通过此练习,您将学会在 WebSocket 中传输文件数据并实现文件预览。


注意事项

WebSocket 性能优化

  • 消息压缩:在高并发场景下,使用 compression 中间件压缩消息。
  • 连接池管理:限制同时连接数,避免服务器过载。
  • 负载均衡:使用 AWS ELB 分发请求。
  • 心跳检测:定期发送心跳包检测连接状态。

安全考虑

  • 验证文件类型和大小,防止恶意上传。
  • 使用 HTTPS 加密 WebSocket 通信。

学习建议

  • 边读边实践,参考 Socket.IO 文档 和 Framer Motion 文档。
  • 尝试集成 AI 辅助功能(如智能回复),探索 2025 年趋势。

结语

通过这个实时聊天应用项目,你完整地体验了一个 React 项目从需求分析到上线的全流程。你掌握了 WebSocket 集成、动画效果、状态同步、性能优化和 AWS 部署等核心技能。这些知识将成为你开发复杂应用的坚实基础。

相关文章:

React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用

React 实战项目&#xff1a;实时聊天应用 欢迎来到本 React 开发教程专栏 的第 28 篇&#xff01;在前 27 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和架构模式等核心知识。这一次&#xff0c…...

Go语言中的if else控制语句

if else是Go语言中最基础也最常用的条件控制语句&#xff0c;用于根据条件执行不同的代码块。下面我将详细介绍Go语言中if else的各种用法和特性。 1. 基本语法 1.1. 最简单的if语句 if 条件表达式 {// 条件为true时执行的代码 } 示例&#xff1a; if x > 10 {fmt.Prin…...

【PCIe总线】-- inbound、outbound配置

PCI、PCIe相关知识整理汇总 【PCIe总线】 -- PCI、PCIe相关实现 由之前的PCIe基础知识可知&#xff0c;pcie的组成有&#xff1a;RC&#xff08;根节点&#xff09;、siwtch&#xff08;pcie桥&#xff09;、EP&#xff08;设备&#xff09;。 RC和EP&#xff0c;以及EP和EP能…...

分布式锁实战:Redisson vs. Redis 原生指令的性能对比

分布式锁实战&#xff1a;Redisson vs. Redis 原生指令的性能对比 引言 在DIY主题模板系统中&#xff0c;用户可自定义聊天室的背景、图标、动画等元素。当多个运营人员或用户同时修改同一模板时&#xff0c;若没有锁机制&#xff0c;可能出现“甲修改了背景色&#xff0c;乙…...

MyBatis中foreach集合用法详解

在 MyBatis 中&#xff0c;<foreach> 标签用于遍历集合&#xff08;Collection、List、Array、Map&#xff09;&#xff0c;常用于构建动态 SQL 语句&#xff08;如 IN 查询、批量插入等&#xff09;。以下是详细用法和示例&#xff1a; 核心属性 属性描述collection必填…...

react+taro 开发第五个小程序,解决拼音的学习

1.找一个文件夹 cmd 2.taro init 3.vscode 找开该文件夹cd help-letters 如&#xff1a;我的是(base) PS D:\react\help-letters> pnpm install 4.先编译一下吧。看下开发者工具什么反应。 pnpm dev:weapp 5.开始规则。我用cursor就是不成功。是不是要在这边差不多了&…...

高防IP可以防护什么攻击类型?企业网络安全的第一道防线

“高防IP”成为企业构建网络安全防护体系的重要一环。尤其是对于金融、电商、游戏、政务等业务高度依赖网络稳定性的行业而言&#xff0c;确保系统724小时正常运行已经成为基本要求。高防IP到底可以防护哪些攻击类型&#xff1f;它又是如何帮助企业抵御风险、保障服务稳定运行的…...

Wireshark使用教程(含安装包和安装教程)

Wireshark使用入门教程 0.资源下载以及软件安装1.Wireshark中无法显示网卡列表2.Wireshark抓取H264过程 0.资源下载以及软件安装 参考blog: 抓包神器wireshark安装保姆级教程   压缩包下载&#xff1a;Wireshark安装包 1.Wireshark中无法显示网卡列表 Wireshark中无法显示网…...

Asp.Net Core基于StackExchange Redis 缓存

NuGet安装 StackExchange.Redis Microsoft.Extensions.Options 0. appsettings.json初始化配置 {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHos…...

【Linux】SSH:免密登录

配置 SSH 的免密登录&#xff08;基于公钥认证&#xff09;可实现无需输入密码即可登录远程主机&#xff0c;常用于自动化脚本、服务器集群、DevOps 等场景。 生成本地 SSH 密钥对&#xff08;若尚未存在&#xff09; 在本地客户端执行&#xff1a; ssh-keygen -t rsa -b 409…...

kafka(windows)

目录 介绍 下载 配置 测试 介绍 Kafka是一个分布式流媒体平台&#xff0c;类似于消息队列或企业信息传递系统。 下载 Kafka对于Zookeeper是强依赖&#xff0c;所以安装Kafka之前必须先安装zookeeper 官网&#xff1a;Apache Kafka 下载此安装包并解压 配置 新建log…...

深度学习习题3

1.训练神经网络过程中&#xff0c;损失函数在一些时期&#xff08;Epoch&#xff09;不再减小, 原因可能是&#xff1a; 1.学习率太低 2.正则参数太大 3.卡在了局部最小值 A1 and 2 B. 2 and 3 C. 1 and 3 D. 都是 2.对于分类任务&#xff0c;我们不是将神经网络中的随机权重…...

勒让德多项式

勒让德多项式 (Legendre) 当区间为 [ − 1 , 1 ] [-1,1] [−1,1]&#xff0c;权函数 ρ ( x ) 1 ρ(x)1 ρ(x)1时&#xff0c;由 1 , x , . . . , x n , . . . {1,x,...,x^n,...} 1,x,...,xn,...正交化得到的多项式称为勒让德多项式&#xff0c;并用 P 0 ( x ) , P 1 ( x ) ,…...

atc abc409E

原题链接&#xff1a;E - Pair Annihilation 题目背景&#xff1a; n 个点 n - 1 条边的有权无向图&#xff0c;每个点都有一个值&#xff0c;两个连通的点的值可以互相抵消&#xff0c;既将u 的 -1 传给 v 时可以抵消掉 v 的 1 并花费边权值&#xff1b;求最小花费。 考察算…...

Mysql批处理写入数据库

在学习mybatisPlus时&#xff0c;看到一个原本没用过的参数&#xff1a; rewriteBatchedStatementstrue 将上述代码装入jdbc的url中即可使数据库启用批处理写入。 需要注意的是&#xff0c;这个参数仅适用于MySQL JDBC 驱动的私有扩展参数。 作用原理是&#xff1a; 原本的…...

基于安卓的文件管理器程序开发研究源码数据库文档

摘 要 伴随着现代科技的发展潮流&#xff0c;移动互联网技术快速发展&#xff0c;各种基于通信技术的移动终端设备做的也越来越好了&#xff0c;现代智能手机大量的进入到了我们的生活中。电子产品的各种软硬技术技术的发展&#xff0c;操作系统的不断更新换代&#xff0c;谷歌…...

EMC VNXe 存储系统日志收集方法

写在前面 有朋友找来看看VNXe的故障&#xff0c;这种问题总是要收集日志&#xff0c;顺便这里也分享给大家。 注意&#xff0c;VNXe和VNX 属于完全不同的产品&#xff0c;不要看名字很类似&#xff0c;操作系统已经完全重构了&#xff0c;如果说是否有联系&#xff0c;大概就…...

嵌入式链表操作原理详解

嵌入式链表操作原理详解 链表是嵌入式软件开发中最基础的数据结构之一&#xff0c;其设计采用嵌入式链表节点的思想&#xff0c;实现了高度通用的链表管理机制。以下是核心原理和操作的全面解析&#xff1a; 一、基础数据结构 struct list_head {struct list_head *next, *pr…...

从“人找政策”到“政策找人”:智能退税ERP数字化重构外贸生态

离境退税新政核心内容与外贸企业影响 &#xff08;一&#xff09;政策核心变化解析 退税商店网络扩容 新政明确鼓励在大型商圈、旅游景区、交通枢纽等境外旅客聚集地增设退税商店&#xff0c;并放宽备案条件至纳税信用M级企业。以上海为例&#xff0c;静安区计划新增1000家退…...

一.设计模式的基本概念

一.核心概念 对软件设计中重复出现问题的成熟解决方案&#xff0c;提供代码可重用性、可维护性和扩展性保障。核心原则包括: 1.1. 单一职责原则‌ ‌定义‌&#xff1a;一个类只承担一个职责&#xff0c;避免因职责过多导致的代码耦合。 1.2. 开闭原则‌ ‌定义‌&#xf…...

以人类演示视频为提示,学习可泛化的机器人策略

25年5月来自清华大学、上海姚期智研究院和星动纪元&#xff08;RoboEra&#xff09;公司的论文“Learning Generalizable Robot Policy with Human Demonstration Video as a Prompt”。 最近的机器人学习方法通​​常依赖于从通过遥操作收集的大量机器人数据集中进行模仿学习…...

split方法

在编程中&#xff0c;split 方法通常用于将字符串按照指定的分隔符拆分成多个部分&#xff0c;并返回一个包含拆分结果的列表&#xff08;或数组&#xff09;。不同编程语言中的 split 方法语法略有不同&#xff0c;但核心功能相似。以下是常见语言中的用法&#xff1a; ​1. P…...

SOC-ESP32S3部分:36-适配自己的板卡

飞书文档https://x509p6c8to.feishu.cn/wiki/RP4UwPrsKi4xuQkKLAAcKxD3n1b 如果你自己画了PCB板&#xff0c;需要把自己绘制的板卡配置小智AI工程&#xff0c;可以参考此文档。 下载源码 克隆或下载源码到本地&#xff0c;这里以1.5.5为例&#xff0c;大家可以自行修改其它版…...

LLMs 系列科普文(8)

八、模型的自我认知 接下来我们聊聊另一种问题&#xff0c;即模型的自我认知。 网上经常经常可以看到人们会问大语言模型一些关于认知方面的问题&#xff0c;比如“你是什么模型&#xff1f;谁创造了你&#xff1f;” 说实话&#xff0c;其实这个问题有点无厘头。 之所以这么…...

【明日方舟 × 红黑树】干员调度如何不掉线?算法工程的平衡魔法全揭秘!

【明日方舟 红黑树】干员调度如何不掉线&#xff1f;算法工程的平衡魔法全揭秘&#xff01; 作者&#xff1a;星之辰 标签&#xff1a;#红黑树 #明日方舟 #工程平衡树 #算法科普 #动态数据结构 引子&#xff1a;为什么你的干员调度能实时平衡&#xff0c;从不崩盘&#xff1f;…...

Vue3 + Vite 中使用 Lodash-es 的防抖 debounce 详解

Vue3 Vite 中使用 Lodash-es 的防抖(debounce)详解 在 Vue3 Vite 项目中&#xff0c;debounce 是 lodash-es 中最常用的功能之一&#xff0c;它可以帮助我们优化高频事件的处理。下面我将详细讲解 debounce 的使用方法&#xff0c;并提供一个完整的示例。 Debounce 核心概念…...

机器学习基础相关问题

机器学习相关的基础问题 K-means是否一定会收敛 K-means是否一定会收敛 K-means算法在有限步数内一定会收敛&#xff0c;但收敛到的可能是局部最优解而非全局最优解。以下是详细分析&#xff1a; K-means 的优化目标是最小化 样本到其所归属簇中心的距离平方和&#xff08;SSE…...

验证负载均衡与弹性伸缩

什么是弹性伸缩&#xff08;Auto Scaling&#xff09;&#xff1f; 弹性伸缩是指 云计算平台根据实时负载自动调整计算资源&#xff08;如服务器实例、容器Pod&#xff09;数量&#xff0c;以确保系统在高峰时保持稳定&#xff0c;在低谷时节省成本。 什么时候会触发弹性伸缩&…...

Three.js中AR实现详解并详细介绍基于图像标记模式AR生成的详细步骤

文档地址 Three.js中AR实现详解 以下是Three.js中实现AR功能的详细解析&#xff0c;涵盖技术原理、实现步骤、核心组件及优化策略&#xff1a; &#x1f9e9; 一、技术基础 AR.js框架的核心作用 AR.js是Three.js实现AR的基石&#xff0c;提供以下核心能力&#xff1a; 多模…...

CSS高级技巧及新增属性

CSS高级技巧及新增属性 jarringslee 文章目录 CSS高级技巧及新增属性精灵图 Sprite字体图标 iconfontCSS几何图形的写法更改鼠标样式更改表单轮廓取消文本域的拖拽行内块元素的垂直居中对齐溢出文字处理 CSS布局技巧CSS5新增内容及其他属性新增选择器新增基础属性及其他属性ca…...