React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

news2025/6/10 16:47:12

React 实战项目:微前端与模块化架构

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

本项目的目标是为高级开发者提供一个全面的 React 开发体验。通过构建一个由多个 React 模块组成的门户网站,你将学习如何分析需求、选择技术栈、实现复杂功能、优化性能并最终部署上线。本教程不仅提供清晰的指引和丰富的代码示例,还融入 2025 年的技术趋势,如微前端架构和模块联邦(Module Federation)。

引言

微前端架构是现代 Web 开发中最具挑战性和实用性的架构模式之一。它允许将大型应用拆分为多个独立模块,由不同团队开发、部署和维护,同时在运行时组合成一个完整的用户体验。在本项目中,我们将构建一个门户网站,支持多团队协作、模块拆分、懒加载和错误处理等特性。通过这个项目,你将掌握 React 在微前端架构中的高级应用,并学习如何优化和部署一个生产级应用。

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

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

  • 需求分析:将业务需求转化为技术实现。
  • 技术栈选择:根据项目需求选择合适的工具。
  • 模块拆分:使用 Module Federation 和 qiankun 实现微前端。
  • 通信机制:实现模块间通信和状态共享。
  • 懒加载:优化模块加载性能。
  • 错误处理:确保应用健壮性。
  • 部署上线:将应用部署到 Kubernetes。

让我们开始吧!


需求分析

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

  1. 多团队协作
    • 支持多个团队独立开发和部署模块。
    • 模块间通信和状态共享。
  2. 大型应用拆分
    • 将应用拆分为多个独立模块,如导航、内容、用户中心等。
    • 支持模块的动态加载和卸载。
  3. 模块化架构
    • 支持模块间的松耦合,确保模块可独立开发和测试。
    • 支持模块的版本控制和更新。
  4. 性能优化
    • 支持懒加载和代码分割,减少初始加载时间。
    • 支持模块的预加载和缓存。
  5. 错误处理
    • 支持模块的错误隔离和恢复。
    • 提供友好的错误提示和日志记录。
  6. 部署和维护
    • 支持模块的独立部署和更新。
    • 支持应用的灰度发布和回滚。

需求背后的意义

这些需求覆盖了微前端架构的核心场景,同时为学习 React 提供了丰富的实践机会:

  • 多团队协作:通过模块间通信和状态共享,解决团队间协作问题。
  • 大型应用拆分:使用 Module Federation 和 qiankun 实现模块化。
  • 模块化架构:松耦合设计提升开发效率和可维护性。
  • 性能优化:通过懒加载和代码分割提升用户体验。
  • 错误处理:确保应用的健壮性和稳定性。
  • 部署和维护:支持灰度发布和回滚,提升生产环境可靠性。

这些需求还为微前端架构的长期维护提供了实际场景,确保应用在扩展和迭代中依然高效。


技术栈选择

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

  • React
    核心前端框架,用于构建用户界面。React 的组件化和声明式编程提升开发效率。
  • Module Federation
    Webpack 5 的模块联邦特性,支持运行时动态加载和共享模块。
  • qiankun
    基于 single-spa 的微前端框架,支持多种技术栈。
  • Redux Toolkit
    简化全局状态管理,确保状态一致性。
  • React Query
    管理数据请求和缓存,提升性能。
  • Kubernetes
    提供高可用性和可扩展性,支持应用的部署和维护。

技术栈优势

  • React:生态丰富,社区活跃,适合快速开发。
  • Module Federation:运行时模块共享,减少重复代码。
  • qiankun:支持多框架集成,灵活性高。
  • Redux Toolkit:简化状态管理,减少样板代码。
  • React Query:自动管理数据同步,提升用户体验。
  • Kubernetes:支持容器化部署,确保高可用性。

这些工具组合易于上手,符合 2025 年 React 开发的最佳实践。


项目实现

现在进入核心部分——代码实现。我们将从项目搭建开始,逐步完成模块拆分、通信机制、状态共享、懒加载、错误处理和部署。

1. 项目搭建

使用 Vite 创建一个 React 项目:

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

安装必要的依赖:

npm install @reduxjs/toolkit react-redux @tanstack/react-query qiankun

2. 模块拆分

我们将应用拆分为多个独立模块:导航、内容和用户中心。

模块结构
  • 导航模块:负责顶部导航栏。
  • 内容模块:负责主内容展示。
  • 用户中心模块:负责用户资料和设置。
文件结构
portal/
├── src/
│   ├── components/
│   │   ├── Navigation.tsx
│   │   ├── Content.tsx
│   │   └── UserCenter.tsx
│   ├── features/
│   │   ├── auth/
│   │   │   └── authSlice.ts
│   │   └── dashboard/
│   │       └── dashboardSlice.ts
│   ├── pages/
│   │   ├── index.tsx
│   │   └── dashboard.tsx
│   ├── App.tsx
│   └── main.tsx
├── public/
└── package.json

3. 使用 Module Federation 实现微前端

我们将使用 Webpack 的 Module Federation 配置独立模块。

配置主应用

在主应用中配置 vite.config.js(需安装 vite-plugin-federation):

npm install @originjs/vite-plugin-federation --save-dev

vite.config.js

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'portal',
      remotes: {
        navigation: 'http://localhost:3001/assets/remoteEntry.js',
        content: 'http://localhost:3002/assets/remoteEntry.js',
        userCenter: 'http://localhost:3003/assets/remoteEntry.js',
      },
      shared: ['react', 'react-dom', 'react-redux', '@reduxjs/toolkit'],
    }),
  ],
  build: {
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
  },
});
配置导航模块

创建独立导航模块项目:

npm create vite@latest navigation -- --template react
cd navigation
npm install

vite.config.js

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/vite-plugin-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'navigation',
      filename: 'remoteEntry.js',
      exposes: {
        './Navigation': './src/Navigation.tsx',
      },
      shared: ['react', 'react-dom', 'react-redux', '@reduxjs/toolkit'],
    }),
  ],
  build: {
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
  },
});

src/Navigation.tsx

import { useSelector } from 'react-redux';

function Navigation() {
  const user = useSelector((state) => state.auth.user || { name: 'Guest' });

  return (
    <nav style={{ background: '#333', color: '#fff', padding: '1rem' }}>
      <h1>导航栏</h1>
      <p>欢迎,{user.name}</p>
    </nav>
  );
}

export default Navigation;

类似地,配置内容模块和用户中心模块,分别监听端口 3002 和 3003。

4. 通信机制与状态共享

使用 Redux Toolkit 管理全局状态。

配置 Redux Store

src/store.ts

import { configureStore } from '@reduxjs/toolkit';
import authReducer from './features/auth/authSlice';

export const store = configureStore({
  reducer: {
    auth: authReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
认证切片

src/features/auth/authSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface AuthState {
  user: { name: string } | null;
  token: string | null;
  role: string;
}

const initialState: AuthState = {
  user: null,
  token: null,
  role: '',
};

export const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    setUser: (state, action: PayloadAction<{ user: { name: string }; token: string; role: string }>) => {
      state.user = action.payload.user;
      state.token = action.payload.token;
      state.role = action.payload.role;
    },
    logout: (state) => {
      state.user = null;
      state.token = null;
      state.role = '';
    },
  },
});

export const { setUser, logout } = authSlice.actions;
export default authSlice.reducer;
主应用集成

src/main.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
使用 qiankun 增强微前端

安装 qiankun:

npm install qiankun

src/main.tsx(更新):

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { registerMicroApps, start } from 'qiankun';
import { store } from './store';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

registerMicroApps([
  {
    name: 'navigation',
    entry: 'http://localhost:3001',
    container: '#navigation-container',
    activeRule: '/',
  },
  {
    name: 'content',
    entry: 'http://localhost:3002',
    container: '#content-container',
    activeRule: '/',
  },
  {
    name: 'userCenter',
    entry: 'http://localhost:3003',
    container: '#user-center-container',
    activeRule: '/user',
  },
]);

start();

src/App.tsx

import React, { Suspense } from 'react';

const Navigation = React.lazy(() => import('navigation/Navigation'));
const Content = React.lazy(() => import('content/Content'));
const UserCenter = React.lazy(() => import('userCenter/UserCenter'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>加载导航中...</div>}>
        <div id="navigation-container">
          <Navigation />
        </div>
      </Suspense>
      <Suspense fallback={<div>加载内容中...</div>}>
        <div id="content-container">
          <Content />
        </div>
      </Suspense>
      <Suspense fallback={<div>加载用户中心中...</div>}>
        <div id="user-center-container">
          <UserCenter />
        </div>
      </Suspense>
    </div>
  );
}

export default App;

5. 懒加载与性能优化

使用 React.lazy 和 Suspense 实现模块懒加载:

src/pages/dashboard.tsx

import React, { lazy, Suspense } from 'react';

const Content = lazy(() => import('content/Content'));

function Dashboard() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <Content />
    </Suspense>
  );
}

export default Dashboard;
预加载优化

添加预加载逻辑:

const preloadModule = (factory: () => Promise<any>) => {
  factory().then(() => console.log('模块预加载完成'));
};

preloadModule(() => import('content/Content'));

6. 错误处理

使用 Error Boundary 隔离模块错误:

src/components/ErrorBoundary.tsx

import { Component, ReactNode } from 'react';

interface ErrorBoundaryProps {
  children: ReactNode;
}

interface ErrorBoundaryState {
  hasError: boolean;
}

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: any) {
    return { hasError: true };
  }

  componentDidCatch(error: any, errorInfo: any) {
    console.error('Error caught:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <h1>发生错误,请稍后重试</h1>;
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

App.tsx 中使用:

import React, { Suspense } from 'react';
import ErrorBoundary from './components/ErrorBoundary';

const Navigation = React.lazy(() => import('navigation/Navigation'));
const_content = React.lazy(() => import('content/Content'));

function App() {
  return (
    <div>
      <ErrorBoundary>
        <Suspense fallback={<div>加载导航中...</div>}>
          <div id="navigation-container">
            <Navigation />
          </div>
        </Suspense>
      </ErrorBoundary>
      <ErrorBoundary>
        <Suspense fallback={<div>加载内容中...</div>}>
          <div id="content-container">
            <Content />
          </div>
        </Suspense>
      </ErrorBoundary>
    </div>
  );
}

export default App;

7. 数据管理与 React Query

使用 React Query 管理异步数据:

npm install @tanstack/react-query

src/hooks/useUserData.ts

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

const fetchUserData = async () => {
  const response = await fetch('https://api.example.com/user');
  return response.json();
};

export function useUserData() {
  return useQuery({
    queryKey: ['userData'],
    queryFn: fetchUserData,
  });
}

UserCenter.tsx 中使用:

import { useUserData } from '../hooks/useUserData';

function UserCenter() {
  const { data, isLoading, error } = useUserData();

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>加载失败</div>;

  return (
    <div>
      <h2>用户中心</h2>
      <p>用户名: {data.name}</p>
    </div>
  );
}

export default UserCenter;

8. 部署到 Kubernetes

构建项目
npm run build
创建 Docker 镜像

Dockerfile

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install --production

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]

构建镜像:

docker build -t portal:latest .
Kubernetes 部署

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: portal-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: portal
  template:
    metadata:
      labels:
        app: portal
    spec:
      containers:
      - name: portal
        image: portal:latest
        ports:
        - containerPort: 3000
        resources:
          limits:
            cpu: "0.5"
            memory: "512Mi"
          requests:
            cpu: "0.2"
            memory: "256Mi"

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: portal-service
spec:
    selector:
      app: portal
    ports:
      - protocol: TCP
        port: 80
        targetPort: 3000
    type: LoadBalancer

部署:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

检查服务:

kubectl get services

通过 LoadBalancer IP 访问应用。


练习:将现有项目迁移到微前端架构

为巩固所学,设计一个练习:将现有项目迁移到微前端架构。

需求

  • 模块拆分:将现有项目拆分为导航、内容和用户中心模块。
  • 通信机制:使用 Redux Toolkit 实现状态共享。
  • 懒加载:使用 React.lazy 优化加载性能。
  • 错误处理:使用 Error Boundary 隔离错误。

实现步骤

  1. 创建模块
    将现有项目拆分为多个子项目,每个模块独立运行。
  2. 配置 Module Federation
    vite.config.js 中配置模块联邦:
import federation from '@originjs/vite-plugin-federation';

export default {
  plugins: [
    federation({
      name: 'app',
      remotes: {
        navigation: 'http://localhost:3001/assets/remoteEntry.js',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
};
  1. 实现通信
    配置 Redux Store 并共享状态。
  2. 实现懒加载
    使用 React.lazy 加载模块。
  3. 实现错误处理
    添加 Error Boundary。

练习目标

通过此练习,你将掌握将传统项目迁移到微前端架构的技能,提升应用的模块化和可扩展性。


注意事项

  • 微前端的维护成本
    微前端架构虽然灵活,但维护成本较高。模块间通信、版本管理和部署复杂度可能增加,需要权衡利弊。
  • 模块间通信
    避免过度耦合,推荐事件总线或共享状态库。
  • 性能优化
    懒加载和代码分割是关键,需监控加载时间。
  • 错误处理
    确保每个模块独立性,避免单一模块崩溃影响整体。
  • 学习建议
    查阅 Module Federation 文档 和 qiankun 文档。

结语

通过这个门户网站项目,你完整体验了一个 React 项目从需求分析到部署的全流程,掌握了微前端架构、模块拆分、通信机制、状态共享、懒加载、错误处理和 Kubernetes 部署等技能。这些知识将成为你开发复杂应用的坚实基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2406840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程

鸿蒙电脑版操作系统来了&#xff0c;很多小伙伴想体验鸿蒙电脑版操作系统&#xff0c;可惜&#xff0c;鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机&#xff0c;来体验大家心心念念的鸿蒙系统啦&#xff01;注意&#xff1a;虚拟…

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…

yaml读取写入常见错误 (‘cannot represent an object‘, 117)

错误一&#xff1a;yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因&#xff0c;后面把yaml.safe_dump直接替换成yaml.dump&#xff0c;确实能保存&#xff0c;但出现乱码&#xff1a; 放弃yaml.dump&#xff0c;又切…

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…

JDK 17 序列化是怎么回事

如何序列化&#xff1f;其实很简单&#xff0c;就是根据每个类型&#xff0c;用工厂类调用。逐个完成。 没什么漂亮的代码&#xff0c;只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…

倒装芯片凸点成型工艺

UBM&#xff08;Under Bump Metallization&#xff09;与Bump&#xff08;焊球&#xff09;形成工艺流程。我们可以将整张流程图分为三大阶段来理解&#xff1a; &#x1f527; 一、UBM&#xff08;Under Bump Metallization&#xff09;工艺流程&#xff08;黄色区域&#xff…

2.3 物理层设备

在这个视频中&#xff0c;我们要学习工作在物理层的两种网络设备&#xff0c;分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间&#xff0c;需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质&#xff0c;假设A节点要给…

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…

Spring AOP代理对象生成原理

代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】&#xff0c;这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

基于单片机的宠物屋智能系统设计与实现(论文+源码)

本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢&#xff0c;连接红外测温传感器&#xff0c;可实时精准捕捉宠物体温变化&#xff0c;以便及时发现健康异常&#xff1b;水位检测传感器时刻监测饮用水余量&#xff0c;防止宠物…