创建可重用React组件的实用指南

尽管React是全球最受欢迎和使用最广泛的前端框架之一,但许多开发者在重构代码以提高可复用性时仍然感到困难。如果你发现自己在React应用中不断重复相同的代码片段,那你来对地方了。

在本教程中,将向你介绍三个最常见的特征,表明是时候构建一个可重用的 React 组件了。然后我们将继续通过构建一个可重用的布局和两个令人兴奋的 React hooks 来查看一些实际演示。

当你读完后,你就能自己弄清楚什么时候适合创建可重用的 React 组件,以及如何创建。

一、可重用 React 组件的前三个特征

1、重复创建具有相同 CSS 样式的wrappers

知道何时创建可重用组件,我最喜欢的标志是重复使用相同的 CSS 样式。现在,您可能会想,“等一下:为什么不简单地将相同的类名分配给共享相同 CSS 样式的元素呢?你说得完全正确。每次不同组件中的某些元素共享相同的样式时都创建可重用的组件不是一个好主意。事实上,它可能会带来不必要的复杂性。所以你得再问自己一件事:这些通常样式的元素是包装器吗?

请考虑以下登录和注册页面:

// Login.js
import './common.css';function Login() {return (<div className='wrapper'><main>{...}</main><footer className='footer'>{...}</footer></div>);
}// SignUp.js
import './common.css';function Signup() {return (<div className='wrapper'><main>{...}</main><footer className='footer'>{...}</footer></div>);
}

 相同的样式将应用于每个组件的容器 (<div>元素) 和页脚。所以在这种情况下,你可以创建两个可重用的组件 — <Wrapper /> 和 <Footer /> — 并将它们作为 prop 传递给它们。例如,可以按如下方式重构 login 组件:

// Login.js
import Footer from "./Footer.js";function Login() {return (<Wrapper main={{...}} footer={<Footer />} />);
} 

因此,您不再需要在多个页面中导入common.css或创建相同的<div>元素来包装所有内容。

2、重复使用事件侦听器

要将事件侦听器附加到元素上,你可以在 useEffect() 中像这样处理它:

// App.js
import { useEffect } from 'react';function App() {const handleKeydown = () => {alert('key is pressed.');}useEffect(() => {document.addEventListener('keydown', handleKeydown);return () => {document.removeEventListener('keydown', handleKeydown);}}, []);return (...);
}

或者你可以直接在 JSX 中执行此操作,如下所示 button 组件:

// Button.js
function Button() {return (<button type="button" onClick={() => { alert('Hi!')}}>Click me!</button>);
};

当你想向 document 或 window 添加事件侦听器时,你必须使用第一种方法。但是,您可能已经意识到,第一种方法需要使用 useEffect(),addEventListener() 和 removeEventListener() 编写更多代码。因此,在这种情况下,创建自定义 hook 将使您的组件更加简洁。

使用事件侦听器有四种可能的方案:

  • 相同的事件侦听器,相同的事件处理程序
  • 相同的事件侦听器,不同的事件处理程序
  • 不同的事件侦听器,相同的事件处理程序
  • 不同的事件侦听器,不同的事件处理程序

在第一种情况下,您可以创建一个 hook,其中同时定义了事件侦听器和事件处理程序。

// useEventListener.js
import { useEffect } from 'react';export default function useKeydown() {const handleKeydown = () => {alert('key is pressed.');}useEffect(() => {document.addEventListener('keydown', handleKeydown);return () => {document.removeEventListener('keydown', handleKeydown);}}, []);
};

然后,您可以在任何组件中使用此 hook,如下所示:

// App.js
import useKeydown from './useKeydown.js';function App() {useKeydown();return (...);
};
// useEventListener.js
import { useEffect } from 'react';export default function useEventListener({ event, handler} ) {useEffect(() => {document.addEventListener(event, handler);return () => {document.removeEventListener(event, handler);}}, []);
};

然后,您可以在任何组件中使用此 Hook,如下所示:

// App.js
import useEventListener from './useEventListener.js';function App() {const handleKeydown = () => {alert('key is pressed.');}useEventListener('keydown', handleKeydown);return (...);
};

3、重复使用相同的 GraphQL 脚本

在使 GraphQL 代码可重用时,您真的不需要寻找迹象。对于复杂的应用程序,用于查询或更改的 GraphQL 脚本很容易占用 30-50 行代码,因为要请求的属性很多。如果您多次使用同一个 GraphQL 脚本,我认为它应该有自己的自定义hook。

import { gql, useQuery } from "@apollo/react-hooks";const GET_POSTS = gql`query getPosts {getPosts {user {idname...}emojis {id...}...}
`;const { data, loading, error } = useQuery(GET_POSTS, {fetchPolicy: "network-only"
});

与其在每个从后端请求的页面中重复此代码,不如为这个特定的 API 创建一个 React hook:

import { gql, useQuery } from "@apollo/react-hooks";function useGetPosts() {const GET_POSTS = gql`{...}`;const { data, loading, error } = useQuery(GET_POSTS, {fetchPolicy: "network-only"});return [data];
}const Test = () => {const [data] = useGetPosts();return (<div>{data?.map(post => <h1>{post.text}</h1>)}</div>);
};

二、构建三种可重用的 React 组件

1、布局组件

React 通常用于构建复杂的 Web 应用程序。这意味着需要在 React 中开发大量页面,我怀疑应用程序的每个页面都会有不同的布局。例如,由 30 个页面组成的 Web 应用程序通常使用少于 5 种不同的布局。因此,构建可在许多不同页面中使用的灵活、可重用的布局至关重要。这将为您节省大量代码,从而节省大量时间。

考虑以下 React 功能组件:

import React from "react";
import style from "./Feed.module.css";export default function Feed() {return (<div className={style.FeedContainer}><header className={style.FeedHeader}>Header</header><main className={style.FeedMain}>{<div className={style.ItemList}>{itemData.map((item, idx) => (<div key={idx} className={style.Item}>{item}</div>))}</div>}</main><footer className={style.FeedFooter}>Footer</footer></div>);
}const itemData = [1, 2, 3, 4, 5];

这是一个典型的网页,其中包含 <header>、<main> 、<footer>。如果还有 30 个这样的网页,你很容易厌倦重复编写 HTML 标签和一遍又一遍地应用相同的样式。

相反,您可以创建一个接收 <header>、<main><footer>作为props的布局组件。

// Layout.js
import React from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";export default function Layout({ header, main, footer }) {return (<div className={style.Container}><header className={style.Header}>{header}</header><main className={style.Main}>{main}</main><footer className={style.Footer}>{footer}</footer></div>);
}Layout.propTypes = {main: PropTypes.element.isRequired,header: PropTypes.element,footer: PropTypes.element
};
// Feed.js
import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";export default function Feed() {return (<Layoutheader={<div className={style.FeedHeader}>Header</div>}main={<div className={style.ItemList}>{itemData.map((item, idx) => (<div key={idx} className={style.Item}>{item}</div>))}</div>}footer={<div className={style.FeedFooter}>Footer</div>}/>);
}const itemData = [1, 2, 3, 4, 5];
创建具有粘性元素布局的专业提示

许多开发人员在想要将页眉粘贴到视区顶部或将页脚粘贴到底部时,倾向于使用 position: fixed 或 position: absolute。但是,对于布局,您应该尽量避免这种情况。

由于布局的元素将是传递的 props 的父元素,因此您希望保持布局元素的样式尽可能简单——以便传递<header> 、 <main>或 <footer> 能按预期设置样式。因此,我建议将 position: fixed 和 display: flex 应用于布局的最外层元素,并设置 overflow-y: scroll 到该<main>元素。

/* Layout.module.css */
.Container {/* Flexbox */display: flex;flex-direction: column;/* Width & Height */width: 100%;height: 100%;/* Misc */overflow: hidden;position: fixed;
}.Main {/* Width & Height */width: 100%;height: 100%;/* Misc */overflow-y: scroll;
}

现在,让我们将一些样式应用于你的 Feed 页面:

/* Feed.module.css */
.FeedHeader {/* Width & Height */height: 70px;/* Color & Border */background-color: teal;color: beige;
}.FeedFooter {/* Width & Height */height: 70px;/* Color & Border */background-color: beige;color: teal;
}.ItemList {/* Flexbox */display: flex;flex-direction: column;
}.Item {/* Width & Height */height: 300px;/* Misc */color: teal;
}.FeedHeader,
.FeedFooter,
.Item {/* Flexbox */display: flex;justify-content: center;align-items: center;/* Color & Border */border: 1px solid teal;/* Misc */font-size: 35px;
}

2、事件侦听器

通常,同一个事件侦听器在整个 Web 应用程序中被多次使用。在这种情况下,创建自定义 React 钩子是个好主意。让我们通过开发一个 useScrollSaver 钩子来学习如何做到这一点,它保存用户设备在页面上的滚动位置——这样用户就不需要从顶部再次滚动。这个钩子对于列出大量元素(例如帖子和评论)的网页很有用。

让我们分解以下代码:

export default function useScrollSaver(scrollableDiv, pageUrl) {/* Save the scroll position */const handleScroll = () => {sessionStorage.setItem(`${pageUrl}-scrollPosition`,scrollableDiv.current.scrollTop.toString());};useEffect(() => {if (scrollableDiv.current) {const scrollableBody = scrollableDiv.current;scrollableBody.addEventListener("scroll", handleScroll);return function cleanup() {scrollableBody.removeEventListener("scroll", handleScroll);};}}, [scrollableDiv, pageUrl]);/* Restore the saved scroll position */useEffect(() => {if (scrollableDiv.current &&sessionStorage.getItem(`${pageUrl}-scrollPosition`)) {const prevScrollPos = Number(sessionStorage.getItem(`${pageUrl}-scrollPosition`));scrollableDiv.current.scrollTop = prevScrollPos;}}, [scrollableDiv, pageUrl]);
}

你可以看到 useScrollSaver 钩子需要接收两个参数:scrollableDiv,它必须是一个可滚动的容器,就像上面布局中的<main>,以及 pageUrl,它将用作页面的标识符,以便你可以存储多个页面的滚动位置。

第 1 步:保存滚动位置

首先,您需要将 “scroll” 事件侦听器绑定到可滚动容器:

const scrollableBody = scrollableDiv.current;
scrollableBody.addEventListener("scroll", handleScroll);
return function cleanup() {scrollableBody.removeEventListener("scroll", handleScroll);
};

现在,每次用户滚动 scrollableDiv 时,都会运行一个名为 handleScroll 的函数。在这个函数中,你应该使用 localStorage 或 sessionStorage 来保存滚动位置。区别在于 localStorage 中的数据不会过期,而 sessionStorage 中的数据会在页面会话结束时被清除。您可以使用 setItem(id: string, value: string) 将数据保存在任一存储中:

const handleScroll = () => {sessionStorage.setItem(`${pageUrl}-scrollPosition`,scrolledDiv.current.scrollTop.toString());
};
第 2 步:恢复滚动位置

当用户返回网页时,应将用户定向到它或它之前的滚动位置 — 如果有的话。这个位置数据目前保存在 sessionStorage 中,你需要把它拿出来使用。您可以使用 getItem(id: string) 从存储中获取数据。然后,您只需将可滚动容器的 scroll-top 设置为此获取的值:

const prevScrollPos = Number(sessionStorage.getItem(`${pageUrl}scrollPosition`)
);
scrollableDiv.current.scrollTop = prevScrollPos;
第 3 步:在任何网页中使用 useScrollSaver 钩子

现在你已经完成了自定义钩子的创建,你可以在任何你想要的网页中使用这个钩子,只要你把两个必需的项目传递给钩子:scrollableDiv 和 pageUrl。让我们回到 Layout.js 并在其中使用您的钩子。这将允许使用此布局的任何网页享受您的滚动保护程序:

// Layout.js
import React, { useRef } from "react";
import style from "./Layout.module.css";
import PropTypes from "prop-types";
import useScrollSaver from "./useScrollSaver";export default function Layout({ header, main, footer }) {const scrollableDiv = useRef(null);useScrollSaver(scrollableDiv, window.location.pathname);return (<div className={style.Container}><header className={style.Header}>{header}</header><main ref={scrollableDiv} className={style.Main}>{main}</main><footer className={style.Footer}>{footer}</footer></div>);
}

3、查询/更改(特定于 GraphQL)

如果您像我一样喜欢将 GraphQL 与 React 一起使用,您可以通过为 GraphQL 查询或更改创建 React 钩子来进一步减少您的代码库。

请考虑以下运行 GraphQL 查询 getPosts() 的示例:

import { gql, useQuery } from "@apollo/react-hooks";const GET_POSTS = gql`query getPosts {getPosts {user {idname...}emojis {id...}...}
`;const { data, loading, error } = useQuery(GET_POSTS, {fetchPolicy: "network-only"
});

如果要从后端请求的属性越来越多,您的 GraphQL 脚本将占用越来越多的空间。因此,无需在每次需要运行查询 getPosts() 时都重复 GraphQL 脚本和 useQuery,而是可以创建以下 React 钩子:

// useGetPosts.js
import { gql, useQuery } from "@apollo/react-hooks";export default function useGetPosts() {const GET_POSTS = gql`query getPosts {getPosts {user {idname...}emojis {id...}...}`;const { data, loading, error } = useQuery(GET_POSTS, {fetchPolicy: "network-only"});return [data, loading, error];
}

然后,您可以按如下方式使用 useGetPosts() 钩子:

// Feed.js
import React from "react";
import Layout from "./Layout";
import style from "./Feed.module.css";
import useGetPosts from "./useGetPosts.js";export default function Feed() {const [data, loading, error] = useGetPosts();return (<Layoutheader={<div className={style.FeedHeader}>Header</div>}main={<div className={style.ItemList}>{data?.getPosts.map((item, idx) => (<div key={idx} className={style.Item}>{item}</div>))}</div>}footer={<div className={style.FeedFooter}>Footer</div>}/>);
}

三、关于创建可重用 React 组件的常见问题解答

1、React.js 中的可重用组件是什么?

React.js 中的可重用组件是封装用户界面 (UI) 功能的特定部分的基本代码块,从而能够以模块化和高效的方式构建应用程序。这些组件旨在在整个应用程序甚至不同项目中使用,提供一定程度的代码可重用性,从而显著简化开发。它们通过封装其逻辑和渲染来促进明确的关注点分离,确保其内部实现细节对应用程序的其余部分保持隐藏。这不仅增强了代码的组织和可维护性,还使开发人员能够通过跨团队和项目共享和重用组件来更加协作。

可重用组件的主要优点之一是它们能够保持用户界面的一致性。通过在应用程序的不同部分使用相同的组件,您可以确保统一的外观和感觉,遵守设计准则并创建更精致的用户体验。这些组件通过 props 进行参数化,允许自定义和适应各种用例。此参数化功能在一致性和灵活性之间提供了平衡,使开发人员能够根据每个应用程序功能或页面的特定要求微调组件行为和外观。

可重用性不仅可以节省时间和精力,还可以简化测试过程。隔离和封装的组件更易于测试,您可以创建单元测试来验证其正确性和功能。通过将可重用组件整合到 React 应用程序中,您可以建立可维护、模块化且一致的代码库,最终提高开发效率并提高用户界面的整体质量。

2、React 中可重用组件的示例是什么?

React 中可重用组件的一个常见示例是 “Button” 组件。按钮是用户界面的基本部分,在整个应用程序中用于各种交互。在 React 中创建可重用的 Button 组件可以让你保持一致的外观和行为,同时减少代码重复。下面是一个可重用的 Button 组件的简单示例:

import React from 'react';const Button = ({ label, onClick, style }) => {
return (
<button
style={style}
onClick={onClick}
>
{label}
</button>
);
};export default Button;

在此示例中,Button 组件被封装成一个功能组件,它接收三个关键属性:“label”用于按钮上显示的文本,“onClick”用于单击事件处理程序,以及一个可选的“style”属性用于自定义按钮的外观。此组件封装了按钮的 HTML 结构和行为,使其在整个应用程序中易于重用,而无需复制代码。

此 Button 组件的使用展示了其可重用性和灵活性。在父组件(在本例中为 “App”)中,您可以传入特定的标签文本、单击事件处理函数和样式首选项,以创建具有不同用途和外观的不同按钮。通过使用此类可重用组件,您可以保持统一的用户界面样式并提高代码的可维护性。这些组件可以扩展到按钮之外,以包含更复杂的 UI 元素,例如输入字段、卡片或导航栏,从而形成模块化且可维护的 React 应用程序。可重用组件不仅可以加快开发速度,还可以带来更一致、用户友好的界面,该界面符合设计准则和最佳实践。

3、如何在 React 中创建可重用的组件?

在 React.js 中创建可重用组件是构建模块化和可维护应用程序的基本做法。该过程从一个明确的计划开始,您可以在其中确定要封装在组件中的特定功能或用户界面 (UI) 元素。定义组件的用途后,您可以在 React 项目中创建一个新的 JavaScript/JSX 文件。最好按照 React 的命名约定,以大写字母开头命名文件。

在这个新的组件文件中,您可以定义组件的行为和渲染逻辑。组件可以是功能性的,也可以是基于类的,具体取决于您的需要。在参数化组件时,您接受 props 作为输入,这允许您自定义其外观和行为。使用 PropTypes 或 TypeScript 定义 prop 类型可确保类型的安全性和清晰度,从而更容易理解应该如何使用组件。构建组件后,即可在应用程序的其他部分使用。您可以导入和合并它,传入特定的 props 来为每个用例配置其行为。

4、React 中可重用组件有什么好处?

React 中的可重用组件提供了许多好处,可以显着增强开发过程和应用程序的质量。它们通过将复杂的用户界面分解为更小的、独立的构建块来促进模块化,使代码库更有条理和可维护。这些组件专注于特定功能或 UI 元素,允许开发人员独立管理和更新它们,从而降低意外副作用的风险并简化开发过程。

可重用组件的主要优点是它们的可重用性,从而节省时间和精力。您可以在应用程序的不同部分或不同项目中使用相同的组件,而无需重写类似的代码。这不仅加快了开发速度,还确保了一致的用户界面。一致性是另一个关键优势。通过对特定 UI 元素使用相同的组件,您可以保持统一的外观和行为,遵守设计准则并改善用户体验。

此外,可重用组件是高度可定制的。它们接受 props,这使开发人员能够微调其行为和外观以适应不同的用例。这种参数化增强了组件的灵活性和多功能性。当出现问题时,这些隔离的组件更容易测试和调试,从而可以有效地解决问题。此外,通过跨项目共享和重用组件,团队可以更有效地协作,保持统一的 UI 样式,并确保代码一致性,这对于大规模和长期开发工作至关重要。总之,React 中的可重用组件简化了开发,鼓励代码可重用性,保持 UI 一致性,并提供可定制性,最终导致更高效、更高质量的应用程序。

5、在 React 中,什么是好的可重用组件?

React 中设计良好的可重用组件表现出几个关键特征。首先,可重用性是核心属性。创建这些组件时,应确保在应用程序的不同部分甚至单独的项目中使用。为了实现这一点,它们必须高度参数化,允许开发人员通过 prop 自定义它们的外观和行为。这种多功能性是使组件真正可重用的一个基本方面。

封装同样重要。可重用组件应封装其内部逻辑和渲染,从而将实现细节与应用程序的其余部分隔离开来。这种关注点分离可以产生更简洁、更模块化的代码,并简化集成。

模块化是另一个关键属性。好的可重用组件应该具有单一的目的,专注于特定的功能或特定的 UI 元素。这种模块化设计增强了代码的可维护性和调试效率。此外,易于测试至关重要。隔离的组件更易于测试,从而促进创建健壮且可靠的代码。

最后,这些组件应该维护一个清晰的 API,指定它们接受的 props 及其预期用途。这种清晰度有助于其他开发人员了解如何有效地使用组件。当同一组件用于特定 UI 元素时,它们通过促进一致的用户界面,确保应用程序具有凝聚力和用户友好性。从本质上讲,一个好的可重用组件是可重新配置的、封装的、模块化的、易于测试的,并有助于代码的可维护性和 UI 的一致性。

文章翻译自:A Practical Guide to Creating Reusable React Components — SitePoint

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu20.04 Rk3588 交叉编译ffmpeg7.0

firefly 公司出的rk3588的设备&#xff0c;其中已经安装了gcc 交叉编译工具&#xff0c;系统版本是Ubuntu20.04。 使用Ubuntu20.04 交叉编译ffmpeg_ubuntu下配置ffmpeg交叉编译器为arm-linux-gnueabihf-gcc-CSDN博客文章浏览阅读541次。ubuntu20.04 交叉编译ffmpeg_ubuntu下配…

python代码制作数据集的测试和数据质量检测思路

前言 本文指的数据集为通用数据集&#xff0c;并不单是给机器学习领域使用。包含科研和工业领域需要自己制作数据集的。 首先&#xff0c;在制作大型数据集时&#xff0c;代码错误和数据问题可能会非常复杂。 前期逻辑总是简单的&#xff0c;库库一顿写&#xff0c;等排查的时…

Windows系统编程 - 进程遍历

文章目录 前言进程的遍历CreateToolhelp32SnapshotProcess32FirstProcess32Next进程遍历 总结 前言 各位师傅好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解进程遍历的相关知识点 进程的遍历 快照&#xff1a;使用vmware虚拟机的时候&#xff0c;经常需要配置环境服务…

【GD32】(三) ISP基本使用

0 前言 有一块GD32的板子不知道为啥用着用着就下载不了程序了&#xff0c;没办法&#xff0c;只能另寻他法。作为STM32的平替&#xff0c;GD32的功能和STM32基本是一致的&#xff0c;所以也可以使用ISP来下载程序。于是就开始复活这块板子。 1 BOOT模式 对于熟悉STM32开发的人…

【SKFramework框架核心模块】3-2、音频管理模块

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…

开源项目-如何更好的参与开源项目开发

开源之谜-提升自我核心竞争力 一、寻找适合自己的开源项目二、像坐牢一样闭关修炼三、最后的实践 开源代码对所有人开放&#xff0c;开发者可以基于现有代码进行扩展和创新&#xff0c;而不是从零开始&#xff0c;参与开源项目可以提升自我的技术能力&#xff0c;丰富个人的经历…

利用c语言详细介绍下插入排序

插入排序&#xff0c;被称为直接插入排序。它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增 1 的有序表。 一、图文介绍 我们还是使用数组【10&#xff0c;5&#xff0c;3&#xff0c;20&#xff0c;1]&#xff0c;排序使用升序的方式&…

STL——string类常用接口说明

目录 一、string类的介绍 二、string类常用接口的使用说明 1.成员函数 ​编辑 2.迭代器 3.容量 一、string类的介绍 下面是string类的文档对string类的介绍 1.string类是表示字符序列的对象 2.标准字符串类通过类似于标准字符容器的接口为此类对象提供支持&#xff0c…

Excel的图表使用和导出准备

目的 导出Excel图表是很多软件要求的功能之一&#xff0c;那如何导出Excel图表呢&#xff1f;或者说如何使用Excel图表。 一种方法是软件生成图片&#xff0c;然后把图片写到Excel上&#xff0c;这种方式&#xff0c;因为格式种种原因&#xff0c;导出的图片不漂亮&#xff0c…

2024年亚太地区数学建模大赛A题-复杂场景下水下图像增强技术的研究

复杂场景下水下图像增强技术的研究 对于海洋勘探来说&#xff0c;清晰、高质量的水下图像是深海地形测量和海底资源调查的关键。然而&#xff0c;在复杂的水下环境中&#xff0c;由于光在水中传播过程中的吸收、散射等现象&#xff0c;导致图像质量下降&#xff0c;导致模糊、…

【数据分享】2024年我国省市县三级的住宿服务设施数量(8类住宿设施/Excel/Shp格式)

宾馆酒店、旅馆招待所等住宿服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市住宿服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、各区…

一文学习Android系统核心服务ServiceManager

ServiceManager 是 Android 系统中核心的系统服务注册与发现机制&#xff0c;它在 Android Framework 层扮演服务注册中心的角色。它允许进程通过它注册、查询和使用系统服务&#xff0c;实现进程间通信 (IPC) 的基础架构。 ServiceManager 的作用 服务注册&#xff1a;应用程…

DMA理论篇

DMA理论篇 简介 传统的数据传输都是需要CPU来实现&#xff0c;从一个地方拷贝到另一个地方&#xff1b;而DMA(Direct Memory Access)则不完全依赖CPU&#xff0c;DMA更新芯片SOC的一个控制器&#xff0c;他可以控制数据从内存中传输到另一个地方(外设、soc其它模块)&#xff…

SpringBoot 集成 html2Pdf

一、概述&#xff1a; 1. springboot如何生成pdf&#xff0c;接口可以预览可以下载 2. vue下载通过bold如何下载 3. 一些细节&#xff1a;页脚、页眉、水印、每一页得样式添加 二、直接上代码【主要是一个记录下次开发更快】 模板位置 1. 导入pom包 <dependency><g…

IDEA怎么定位java类所用maven依赖版本及引用位置

在实际开发中&#xff0c;我们可能会遇到需要搞清楚代码所用依赖版本号及引用位置的场景&#xff0c;便于排查问题&#xff0c;怎么通过IDEA实现呢&#xff1f; 可以在IDEA中打开项目&#xff0c;右键点击maven的pom.xml文件&#xff0c;或者在maven窗口下选中项目&#xff0c;…

webStorm安装

一、webStorm安装 简介 Webstorm是一款非常受欢迎的优秀开发工具&#xff0c;跟vscode同誉为卧龙凤雏编辑器&#xff0c;是97%开发人员的理想编辑器&#xff0c; 尤其是webstorm&#xff0c;焕然一新的外观&#xff0c;新的导航功能&#xff0c;githob拉取等&#xff0c;更是备…

案例研究|阿特斯的JumpServer分布式部署和多组织管理实践

苏州阿特斯阳光电力科技有限公司&#xff08;以下简称为阿特斯&#xff09;是一家集太阳能光伏组件制造和为全球客户提供太阳能应用产品研发、设计、制造、销售的专业公司。 阿特斯集团总部位于加拿大&#xff0c;中国区总部位于江苏省苏州市。通过全球战略和多元化的市场布局…

数字信号处理(Digital Signal Procession)总结

0、导入库 import numpy as np import matplotlib.pyplot as plt import numpy as np from matplotlib import pyplot as plt from scipy.signal import find_peaks1、创建时域信号 创建时间序列 T 0.01 # 采样间隔 fs 100 # 采样频率 L 1000 # 采样点数 tl 0 # 起始时间…

医院信息化与智能化系统(22)

医院信息化与智能化系统(22) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应…