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

React进阶之高阶组件HOC、react hooks、自定义hooks

React高级

  • 高阶组件 HOC
    • 属性代理
    • 反向继承
    • 属性代理和反向继承的区别
    • 实例
      • 实例一
      • 实例二
  • Hooks
    • Hooks API
      • useState:
      • useEffect:
      • useLayoutEffect:
      • useRef:
      • useContext:
      • useReducer:
      • useMemo
      • useCallback
    • 自定义Hooks

拓展:
ios、安卓、h5、小程序、app在移动端开发上有啥区别?
应用场景不同:

  1. 原生的native app开发,native需要客户端的发版才能做更新迭代
  2. 客户端嵌套页面webview 和 混合应用hybrid app开发 — 要做快的发版,更新迭代的话
  3. mini program - 小程序开发

高阶组件 HOC

hoc:higher order component
本身不是复杂的内容,也不是React官方提供,他是一种设计模式组成的高阶用法,接收一个组件作为参数并返回一个新的组件,React是用组件拼装页面的
简单来说,hoc是组件作为参数,返回值也是组件
HOC 主要用于代码复用,类似于Vue中的mixin

function HOC(WrappedComponent){return props=><WrappedComponent {...props} />
}

这里的props传递可以看作是 vue中的,this.$slots.defaults传递一样

//类的使用
function HOC(WrappedComponent){return class extends React.Component{constructor(props){super(props)}render(){const newProps={name:"zhangsan"}return <WrappedComponent {...props} {...newProps} />}}
}

class类的完整示例:

import React from 'react';// 创建 HOC,增强组件功能:withCounter 是我们定义的高阶组件,它接收一个组件(WrappedComponent)并返回一个新的组件。
function withCounter(WrappedComponent) {return class extends React.Component {constructor(props) {super(props);this.state = { count: 0 };}increment = () => {this.setState(prevState => ({ count: prevState.count + 1 }));};render() {return (<WrappedComponent{...this.props}count={this.state.count}        // 将新的 state(count)传递给原组件increment={this.increment}      // 将新的方法(increment)传递给原组件/>);}};
}// 创建一个基础组件,接收 count 和 increment 作为 props
function Counter({ count, increment }) {return (<div><p>Count: {count}</p><button onClick={increment}>Increment</button></div>);
}// 使用 HOC 包装 Counter 组件
const EnhancedCounter = withCounter(Counter);// 使用增强后的组件
export default function App() {return <EnhancedCounter />;
}

分类:

  1. 属性代理
  2. 反向继承

属性代理

返回的是原本的组件

  1. 代理props
function HOC(WrappedComponent){const newProps = {name:'zhangsan' }return props=><WrappedComponent {...props} {...newProps} />
}
  1. 模拟state
function HOC(WrappedComponent){return class extends React.Component {constructor(props){super(props)this.state = {name:"zhangsan"}this.onChange = this.onChange.bind(this)}onChange=(e)=>{this.setState({name:e.target.value})}render(){const newProps={name: {value: this.state.name,onChange:this.onChange}}return <WrappedComponent {...this.props} {...newProps} />}}
}function Demo(props) {const { name } = propsconst { value, onChange } = name;//props// 定义新的state方法
}// 在外部的组件中定义的state state:name,methods:onChange
// 传递给内部的 WrappedComponent,通过props的方式去传递给他,能够获取value和onChange事件,然后去消费它
  1. 条件渲染,基于返回组件做的自定义处理
function HOC(WrappedComponent) {// customif (show = false) {return <div>暂无数据</div>}return props=> <WrappedComponent {...props} />
}

反向继承

使用类组件的方式
返回的是新的组件

function HOC(WrappedComponent) {return class extends WrappedComponent{render() {return super.render();}}
}

这里,返回的新组件是原先的组件一比一复制过来的。

使用:

function HOC(WrappedComponent) {// componentDidMount 新加功能const didMount = WrappedComponent.prototype.componentDidMount;//原本组件的mount方法return class extends WrappedComponent{// constructor() { this.state=WrappedComponent.prototype.state}componentDidMount() {if (didMount) {//需要将这样的生命周期关联的事件绑定到自定义的类中didMount.bind(this)  //新的组件里面,将原本组件生命周期方法执行了一遍}// handle custom 自定义逻辑this.setState({number:2})}render() {return super.render();}}
}

举例使用:
计算组件渲染时间:

function withTiming(WrappedComponent) {return class extends WrappedComponent{constructor(props) {super(props);start = 0;end = 0;}componentWillMount() {  //继承链上的生命周期方法依次执行,由子到父的顺序执行,也就是说,先执行 withTiming 中的 componentWillMount,然后执行 WrappedComponent 中的 componentWillMountif (super.componentWillMount) {super.componentWillMount();}start+=Date.now()}componentDidMount() { //同理,先执行 withTiming 中的 componentDidMount,然后执行 WrappedComponent 中的 componentDidMountif (super.componentDidMount) {super.componentDidMount();}end += Date.now()console.error(`${WrappedComponent.name}渲染时间为${end - start}ms`) //也就是说,这里统计的渲染时间实际是继承链上所有组件生命周期渲染时间的总和}render() {return super.render();}}
}
export default withTiming(Home)

属性代理和反向继承的区别

属性代理本质上是在外部操作这个组件,由外到内;但是,反向继承是由内到外,返回一个新的组件。所以说,由内部操作的话,是可以操作组件的所有逻辑的,内部逻辑相对比较危险。

实例

实例一

// views/PageA.js
import React from 'react';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';class PageA extends React.Component {state = {movieList: [],}/* ... */async componentDidMount() {const movieList = await fetchMovieListByType('comedy');this.setState({movieList,});}render() {return <MovieList data={this.state.movieList} emptyTips="暂无喜剧"/>}
}
export default PageA;// views/PageB.js
import React from 'react';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';class PageB extends React.Component {state = {movieList: [],}// ...async componentDidMount() {const movieList = await fetchMovieListByType('action');this.setState({movieList,});}render() {return <MovieList data={this.state.movieList} emptyTips="暂无动作片"/>}
}
export default PageB;// 冗余代码过多
// HOC
import React from 'react';const withFetchingHOC = (WrappedComponent, fetchingMethod, defaultProps) => {return class extends React.Component {async componentDidMount() {const data = await fetchingMethod();this.setState({data,});}render() {return (<WrappedComponent data={this.state.data} {...defaultProps} {...this.props} />);}}
}// 使用:
// views/PageA.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';const defaultProps = {emptyTips: '暂无喜剧'}export default withFetchingHOC(MovieList, fetchMovieListByType('comedy'), defaultProps);// views/PageB.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';const defaultProps = {emptyTips: '暂无动作片'}export default withFetchingHOC(MovieList, fetchMovieListByType('action'), defaultProps);;// views/PageOthers.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';
const defaultProps = {...}
export default withFetchingHOC(MovieList, fetchMovieListByType('some-other-type'), defaultProps);

一般在工作中使用到的都是属性代理,很少用到反向继承,在统计性能指标的场景中可以用反向继承。
属性代理效果一般做公用逻辑的抽离
属性代理实例:
不用HOC:
views/PageA.js:

// views/PageA.js
import React from 'react';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';// PageA:喜剧片的渲染
class PageA extends React.Component {state = {movieList: [],}/* ... */async componentDidMount() {const movieList = await fetchMovieListByType('comedy');this.setState({movieList,});}render() {return <MovieList data={this.state.movieList} emptyTips="暂无喜剧"/>}
}
export default PageA;

views/PageB.js

// views/PageB.js
import React from 'react';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';// pageB:动作片的渲染
class PageB extends React.Component {state = {movieList: [],}// ...async componentDidMount() {const movieList = await fetchMovieListByType('action');this.setState({movieList,});}render() {return <MovieList data={this.state.movieList} emptyTips="暂无动作片"/>}
}
export default PageB;

=>冗余代码过多,使用HOC抽离:

// 冗余代码过多
// HOC
import React from 'react';//  包裹的组件        请求的方法     上述的emptyTips
const withFetchingHOC = (WrappedComponent, fetchingMethod, defaultProps) => {return class extends React.Component {async componentDidMount() {const data = await fetchingMethod();this.setState({data,});}render() {return (<WrappedComponent data={this.state.data} {...defaultProps} {...this.props} />);}}
}

views/PageA.js:

// 使用:
// views/PageA.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';const defaultProps = {emptyTips: '暂无喜剧'}export default withFetchingHOC(MovieList, fetchMovieListByType('comedy'), defaultProps);

views/PageB.js:

// views/PageB.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';const defaultProps = {emptyTips: '暂无动作片'}export default withFetchingHOC(MovieList, fetchMovieListByType('action'), defaultProps);

其他页面:

// views/PageOthers.js
import React from 'react';
import withFetchingHOC from '../hoc/withFetchingHOC';
import fetchMovieListByType from '../lib/utils';
import MovieList from '../components/MovieList';
const defaultProps = {...}
export default withFetchingHOC(MovieList, fetchMovieListByType('some-other-type'), defaultProps);

实例二

在vue中有自定义指令,像v-permission,通过自定义指令实现按钮的逻辑展示,但是在这里也能通过HOC来实现。
例如:

import React from 'react';
import { whiteListAuth } from '../lib/utils'; // 鉴权方法function AuthWrapper(WrappedComponent) {return class AuthWrappedComponent extends React.Component {constructor(props) {super(props);this.state = {permissionDenied: -1,};}async componentDidMount() {try {await whiteListAuth(); // 请求鉴权接口this.setState({permissionDenied: 0,});} catch (err) {this.setState({permissionDenied: 1,});}}render() {if (this.state.permissionDenied === -1) {return null; // 鉴权接口请求未完成}if (this.state.permissionDenied) {return <div>功能即将上线,敬请期待~</div>;}return <WrappedComponent {...this.props} />;}}
}export default AuthWrapper;

Hooks

上节内容回顾:

  1. 在props和state两个组件开发过程中,如果要定义组件内部中的变量,使用props还是state?
    state
  2. 在props过程中,props元素随着外部组件变化而变化,如何观察到props的一个变化呢?
    生命周期等,只要能够获取到新的props就可以
  3. props是外部传参的,外部传递参数可能是不同的,想要一个组件要改变它的props,用什么样的方式能够做到呢?
    dispatch,最直接的方式,将props转为state
  4. 将React组件封装的更好,根据这里的思路:官方中文链接,将共有的能力抽离出来,放到对应的state,props上即可。

类组件中不能使用hooks

Hooks API

Hooks官方

结合官网中看下面讲到的几个API就行

use:试验期,在React 19中才会用到,返回的是一个promise的结果,这个方法是用来读取promise的返回值的。能够获取到返回的结果,能够读取到context,不建议使用。

useState:

const [state, setState] = useState(initialState)
initialState:初始默认值,state:默认值的返回,setState就是修改state的方式

import { useState } from 'react';function MyComponent() {const [age, setAge] = useState(28);const [name, setName] = useState('Taylor');const [todos, setTodos] = useState(() => createTodos());  //初始值能够获取函数的返回结果,但是必须是同步的const [userInfo,setUserInfo]=useState({name:"Taylor",age:42})// userInfo.age=52  这种方法是不生效的//这样去修改对象种某个属性的值setUserInfo({...userInfo,age:52})...
}

useEffect:

添加随着状态的改变来触发它的动作,辅佐用,返回的结果用来清除它的辅佐用

import { useEffect } from 'react';
import { createConnection } from './chat.js';function ChatRoom({ roomId }) {const [serverUrl, setServerUrl] = useState('https://localhost:1234');useEffect(() => { //useEffect参数:1.接收一个函数 2.一个数组const connection = createConnection(serverUrl, roomId); //创建长连接connection.connect();return () => {  //返回这里用来销毁连接 connection.disconnect();};}, [serverUrl, roomId]); //当且仅当serverUrl或roomId发生变化时,会重新执行useEffect中的函数// ...
}

使用场景:
可以在请求数据中使用

import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';export default function Page() {const [person, setPerson] = useState('Alice');const [bio, setBio] = useState(null);useEffect(() => {let ignore = false;setBio(null);fetchBio(person).then(result => {if (!ignore) {setBio(result);}});return () => {ignore = true;}}, [person]);return (<><select value={person} onChange={e => {setPerson(e.target.value);}}><option value="Alice">Alice</option><option value="Bob">Bob</option><option value="Taylor">Taylor</option></select><hr /><p><i>{bio ?? 'Loading...'}</i></p></>);
}

代码中的useEffect:

  useEffect(() => {let ignore = false;setBio(null);fetchBio(person).then(result => {if (!ignore) {setBio(result);}});return () => {ignore = true;}}, [person]);

如果第二个返回的数组中person没有值了,那么就是没有依赖项发生变化,就在初始化中执行一次,等同于 componentDidMount

useLayoutEffect:

是useEffect的一个版本,这两个传递的参数都一样,只不过触发setup函数的时间不一样
useEffect: 组件mount -> dom渲染 -> useEffect(()=>{},[deps])
useLayoutEffect:组件mount -> useLayoutEffect(()=>{},[deps]) -> dom渲染

const DemoUseLayoutEffect = () => {const target = useRef()useLayoutEffect(() => {/*我们需要在dom绘制之前,移动dom到制定位置*/const { x ,y } = getPositon() /* 获取要移动的 x,y坐标 */animate(target.current,{ x,y })}, []);return (<div ><span ref={ target } className="animate"></span></div>)
}

这里意味着先执行的useLayoutEffect的回调函数(执行动作animate),再去渲染的return返回中的div代码

需要在dom上渲染最终的结果就使用:useLayoutEffect
需要在dom上展示执行callback回调函数的动作,就使用useEffect

useRef:

与Vue3中的Ref类似,通过 ref.current 获取值,但是创建的 ref 并没有关联到元素上,ref 绑定的是真实的js对象
与 state区别:
const [a,setA]=useState(1) => 当执行setA时候,会执行 重新渲染 re-render
但是如果只想改变值,并不希望组件重新渲染,可以借助ref
const a=useRef(1)
a.current=2 => 不会触发视图的响应,也不会触发视图的更新

使用场景:

const inputRef = useRef(null);
.......
return <input ref={inputRef} />;
function handleClick() {inputRef.current.focus();
}

useContext:

/* 用useContext方式 */
const DemoContext = ()=> {const value = useContext(Context);/ my name is aaa /return <div> my name is { value.name }</div>
}/ 用Context.Consumer 方式 /
const DemoContext1 = ()=>{return <Context.Consumer>{/  my name is aaa  */}{ (value)=> <div> my name is { value.name }</div> }</Context.Consumer>
}export default ()=>{return <div><Context.Provider value={{ name:'aaa' }} ><DemoContext /><DemoContext1 /></Context.Provider></div>
}

创建的Context,是能通过Provider和Consumer两个地方去消费的
第一种是用useContext将我们的值关联起来,
第二种,通过Provider将value值关联起来了,就能在provider下层的所有节点上,这里是DemoContext,DemoContext1,
这两个节点,一方面通过 useContext获取到其中关联的value,另一种是通过Context.Consumer之间去获取。但是在平常开发过程中,一般是通过useContext和Provider去获取上层传递下来的状态

useReducer:

const DemoUseReducer = ()=>{/* number为更新后的state值,  dispatchNumbner 为当前的派发函数 */const [ number , dispatchNumbner ] = useReducer((state, action) => {const { payload , name  } = action/ return的值为新的state /switch(name) {case 'a':return state + 1case 'b':return state - 1 case 'c':return payload       }return state}, 0)return <div>当前值:{ number }{ / 派发更新 / }<button onClick={()=>dispatchNumbner({ name: 'a' })} >增加</button><button onClick={()=>dispatchNumbner({ name: 'b' })} >减少</button><button onClick={()=>dispatchNumbner({ name: 'c' , payload:666 })} >赋值</button>{ / 把dispatch 和 state 传递给子组件  */ }<MyChildren  dispatch={ dispatchNumbner } State={{ number }} /></div>
}

上述这两个useContext 和 useReducer 和Redux的逻辑是一样的

useMemo

是平常做响应式依赖的一个动作,类似于vue中的computed

// selectList 不更新时,不会重新渲染,减少不必要的循环渲染
const a=useMemo(() => (<div>{selectList.map((i, v) => (<spanclassName={style.listSpan}key={v} >{i.patentName} </span>))}</div>
), [selectList])

当selectList元素变化时候,重新执行回调函数,只不过,useMemo返回的结果,就是这个函数执行的结果,所以,在selectList不变的话,哪怕这个组件变化,这个a的结果也不会发生变化
适用于性能优化

// listshow, cacheSelectList 不更新时,不会重新渲染子组件
useMemo(() => (<Modalwidth={'70%'}visible={listshow}footer={[<Button key="back" >取消</Button>,<Buttonkey="submit"type="primary">确定</Button>]}> { /* 减少了PatentTable组件的渲染 */ }<PatentTablegetList={getList}selectList={selectList}cacheSelectList={cacheSelectList}setCacheSelectList={setCacheSelectList}/></Modal>), [listshow, cacheSelectList])
 // 减少组件更新导致函数重新声明const DemoUseMemo = () => {/ 用useMemo 包裹之后的log函数可以避免了每次组件更新再重新声明 ,可以限制上下文的执行 /const newLog = useMemo(() => {const log = () => {console.log(123)}return log}, [])return <div onClick={()=> newLog() } ></div>
}
// 如果没有加相关的更新条件,是获取不到更新之后的state的值的
const DemoUseMemo = () => {const [ number ,setNumber ] = useState(0)const newLog = useMemo(() => {const log = () => {/ 点击span之后 打印出来的number 不是实时更新的number值 /console.log(number)}return log/ [] 没有 number */  }, [])return <div><div onClick={() => newLog()} >打印</div><span onClick={ () => setNumber( number + 1 )  } >增加</span></div>
}

useCallback

useMemo返回的是函数执行的结果,useCallback返回的是这个函数

挂载时初始化,constructor 对应着 useLayoutEffect 初始化
componentDidMount 对应着 useLayoutEffect第二个参数不传
更新 对应着 useEffect 传递参数
shouldComponentUpdate 对应着 useMemo和useCallback
componentDidUpdate 对应着 useEffect 回调函数执行
componentWillUnmount 对应着 useEffect 返回函数的执行

也就是这样:

useLayoutEffect(() => {// componentDidMountreturn () => {// componentWillUnmount};
}, [])useEffect(() => {// componentDidUpdate
}, [deps])// shouldComponentUpdate
useMemo(); useCallback()

自定义Hooks

类似:

const [a,b,c,d]=useXXX(params1,parmas2)

这种形式的就叫做自定义hook
自定义hook中使用reactive中已有的hook

本质上是:用已有的hooks做相同某种功能的聚合,聚合后能够在其他某个地方取消费

const useTitle = (title) => { useEffect(() => { document.title = title; }, []);
}const App = () => {useTitle('Hello World');return <div>Hello World</div>;
}

保证代码是相对独立的

import { useState, useEffect } from 'react'const useScroll = (scrollRef) => {const [pos, setPos] = useState([0,0])useEffect(() => {function handleScroll(e){setPos([scrollRef.current.scrollLeft, scrollRef.current.scrollTop])}scrollRef.current.addEventListener('scroll', handleScroll)return () => {scrollRef.current.removeEventListener('scroll', handleScroll)}}, [])return pos
}export default useScroll// 用法
import React, { useRef } from 'react'
import { useScroll } from 'hooks'const Home = (props) => {const scrollRef = useRef(null)const [x, y] = useScroll(scrollRef)return <div><div ref={scrollRef}><div className="innerBox"></div></div><div>{ x }, { y }</div></div>
}

相关文章:

React进阶之高阶组件HOC、react hooks、自定义hooks

React高级 高阶组件 HOC属性代理反向继承属性代理和反向继承的区别实例实例一实例二 HooksHooks APIuseState&#xff1a;useEffect&#xff1a;useLayoutEffect&#xff1a;useRef&#xff1a;useContext&#xff1a;useReducer:useMemouseCallback 自定义Hooks 拓展&#xff…...

【Pytest】基础到高级功能的理解使用

文章目录 第一部分&#xff1a;Pytest 简介1.1 什么是 Pytest&#xff1f;1.2 Pytest 的历史1.3 Pytest 的核心概念1.4 Pytest 的特点1.5 为什么选择 Pytest&#xff1f; 第二部分&#xff1a;Pytest 的基本使用2.1 安装 Pytest2.2 编写第一个测试用例2.2.1 创建一个简单的测试…...

RHCE实验详解

目录 实验分析 环境拓扑结构 项目需求 主机环境描述 实验步骤 一、密钥互信和主机名更改 二、DNS 三、NGINX 四、MARIADB 五、NFS 六、NTP 七、论坛服务 结果展示及痛点解答 实验分析 环境拓扑结构 项目需求 1. 172.25.250.101 主机上的 Web 服务要求提供 www.ex…...

备赛蓝桥杯之第十五届职业院校组省赛第二题:分享点滴

提示&#xff1a;本篇文章仅仅是作者自己目前在备赛蓝桥杯中&#xff0c;自己学习与刷题的学习笔记&#xff0c;写的不好&#xff0c;欢迎大家批评与建议 由于个别题目代码量与题目量偏大&#xff0c;请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题&#xff0…...

MyBatis 注解开发详解

MyBatis 注解开发详解 MyBatis 支持使用注解来进行数据库操作。注解方式将 SQL 语句直接写在 Java 接口中&#xff0c;通过注解来完成 CRUD&#xff08;增删改查&#xff09;操作&#xff0c;省去了使用 XML 配置的繁琐步骤。这种方式适合简单项目或快速原型开发&#xff0c;因…...

Kivy App开发之UX控件VideoPlayer视频播放

kivy使用VideoPlayer控件实现视频播放,可以控制视频的播放,暂停,音量调节等功能。 在使用VideoPlayer视频播放器时,可以参考下表属性来设置其样式和触发事件。 属性说明source视频路径,默认为空state视频状态,值play,pause,stop,默认为stopthumbnail显示视频的缩略图…...

简单排序算法

异或运算及异或运算实现的swap方法 ^(异或): ^运算是计算机中的位运算&#xff0c;运算规则为相同为0&#xff0c;不同为1&#xff08;也被称为无进位相加&#xff09;。位运算处理效率比常规运算符效率更高。 异或运算遵循的法则&#xff1a; 0^N N N^N 0 异或运算…...

C语言初阶牛客网刷题——JZ17 打印从1到最大的n位数【难度:入门】

1.题目描述 牛客网OJ题链接 题目描述&#xff1a; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 用返回一个整数列表来代替打印n 为正整数&#xff0c;0 < n < 5 示例1 输入&…...

基于springboot+vue的校园二手物品交易系统的设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…...

开发环境搭建-2:配置 python 运行环境(使用 uv 管理 python 项目)

在 WSL 环境中配置&#xff1a;WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 UV 介绍 uv软件官网&#xff08;github 需要梯子&#xff0c;没错这个软件的官网真就是 github 页面&#xff09;&#xff1a;https://github.com/astral-sh/uv 中文官网&#xff08;github 需要梯…...

STM32 ST7735 128*160

ST7735 接口和 STM32 SPI 引脚连接 ST7735 引脚功能描述STM32 引脚连接&#xff08;示例&#xff0c;使用 SPI1&#xff09;SCLSPI 时钟信号 (SCK)PA0(SPI1_SCK)SDASPI 数据信号 (MOSI)PA1 (SPI1_MOSI)RST复位信号 (Reset)PA2(GPIO 手动控制)DC数据/命令选择 (D/C)PA3 (GPIO 手…...

【面试总结】FFN(前馈神经网络)在Transformer模型中先升维再降维的原因

FFN&#xff08;前馈神经网络&#xff09;在Transformer模型中先升维再降维的设计具有多方面的重要原因&#xff0c;以下是对这些原因的总结&#xff1a; 1.目标与动机 高维映射空间&#xff1a;FFN的设计目的是通过一系列线性变换来拟合一个高维的映射空间&#xff0c;而不仅…...

VB读写ini配置文件将运行文件放入任务计划程序设置为开机自启动

本示例使用设备&#xff1a; https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bWmhJZJ&ftt&id562957272162 Public Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpAppl…...

Java基础 (一)

基础概念及运算符、判断、循环 基础概念 关键字 数据类型 分为两种 基本数据类型 标识符 运算符 运算符 算术运算符 隐式转换 小 ------>>> 大 强制转换 字符串 拼接符号 字符 运算 自增自减运算符 ii赋值运算符 赋值运算符 包括 强制转换 关系运算符 逻辑运算符 …...

数据结构——实验六·散列表

嗨~~欢迎来到Tubishu的博客&#x1f338;如果你也是一名在校大学生&#xff0c;正在寻找各种编程资源&#xff0c;那么你就来对地方啦&#x1f31f; Tubishu是一名计算机本科生&#xff0c;会不定期整理和分享学习中的优质资源&#xff0c;希望能为你的编程之路添砖加瓦⭐&…...

springboot网上书城

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括网上书城管理系统的网络应用&#xff0c;在国外网上书城管理系统已经是很普遍的方式&#xff0c;不过国内的书城管理系统可能还处于起步阶段。网上书城管理系统具有网上…...

如何在 Pytest 中使用命令行界面和标记运行测试

关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 在前文你已经初步尝试编写了代码和单元测试&#xff0c;并且想要确保它能正常运行。…...

不建模,无代码,如何构建一个3D虚拟展厅?

在数字化浪潮的推动下&#xff0c;众多企业正积极探索线上3D虚拟展厅这一新型展示平台&#xff0c;旨在以更加生动、直观的方式呈现其产品、环境与综合实力。然而&#xff0c;构建一个既专业又吸引人的3D虚拟展厅并非易事&#xff0c;它不仅需要深厚的技术支持&#xff0c;还需…...

github汉化

本文主要讲述了github如何汉化的方法。 目录 问题描述汉化步骤1.打开github&#xff0c;搜索github-chinese2.打开项目&#xff0c;打开README.md3.下载安装脚本管理器3.1 在README.md中往下滑动&#xff0c;找到浏览器与脚本管理器3.2 选择浏览器对应的脚本管理器3.2.1 点击去…...

Unity Line Renderer Component入门

Overview Line Renderer 组件是 Unity 中用于绘制连续线段的工具。它通过在三维空间中的两个或两个以上的点的数组&#xff0c;并在每个点之间绘制一条直线。可以绘制从简单的直线到复杂的螺旋线等各种图形。 1. 连续性和独立线条 连续性&#xff1a;Line Renderer 绘制的线条…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...