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

React(四) 事件总线,setState的原理,PureComponent优化React性能,ref获取类组件与函数组件

文章目录

  • 一、全局事件总线
  • 二、setState的原理
    • 1. 为什么要使用setState修改数据
    • 2. setState的三种用法
      • (1) 基本使用
      • (2) 传入回调函数
      • (3) setState是一个异步调用
    • 3. setState为什么要设置成异步
  • 二、PureComponent优化性能
    • 1. React的diff算法以及Key的优化(扩展)
      • (1) diff算法
      • (2) 列表中的key属性
    • 2. 引出问题:render函数的优化
    • 3. shouldComponentUpdate
    • 4. PureComponent与memo
      • (1) 类组件
      • (2) 函数式组件
    • 5. PureComponent浅层监测
    • 6. 实现PureComponent深层检测
  • 三、ref获取元素或组件实例
    • 1. ref获取原生DOM的三种方式
    • 2. ref获取类组件实例
    • 2. ref获取函数式组件里的元素

一、全局事件总线

安装第三方库npm install hy-event-store
发送数据的组件触发事件emit('事件名',参数)

// Son.jsxsendData () {// 触发事件,"tom", 100, 7.5是传递的参数eventBus.emit('getData', "tom", 100, 7.5)}render () {return (<div><h2>Son组件</h2><button onClick={this.sendData}>传递数据</button></div>)}

接收数据的组件绑定事件
绑定:xxx.on('事件名',绑定的函数,[this指向的值]) (this指向的值是可选的)
解绑:xxx.off('事件名',绑定的函数)

// App.jsxcomponentDidMount () {// 绑定事件,当getData事件被触发时,调用函数showDataeventBus.on('getData', this.showData)}componentWillUnmount () {// 解绑eventBus.off('getData', this.showData)}showData (name, nums, score) {console.log('showData', name, nums, score,);this.setState({ name, nums, score }) // 此时this指向undefined}

这里同样需要注意this的指向问题。这里有三种方式确定this指向

 componentDidMount () {// 绑定事件// eventBus.on('getData', this.showData)// 方式一: on的第三个参数可指定this指向eventBus.on('getData', this.showData, this)// 方式二: 箭头函数eventBus.on('getData', (name, nums, score) => this.showData(name, nums, score))}// 方式三:es6的class filedsshowData = (name, nums, score) => {this.setState({ name, nums, score })}

二、setState的原理

1. 为什么要使用setState修改数据

Vue和React数据管理与渲染界面的区别:

  因为Vue做了数据劫持,当数据变化时,Vue能够监听到数据的变化,然后底层的set方法调用了render()函数重新渲染页面。所以Vue用起来感觉是会自动渲染,不用我们手动调用render()函数。

  而React没有数据劫持,如果通过this.state.msg = 'xxx'来修改数据,Reac并不知道该数据发生变化,也就不会刷新页面。
如何让React得知数据发生变化?就是调用setState()来修改数据,调用这个函数就相当于通知React数据发生了更新,需要重新渲染界面,React就会调用render()函数。

总结:
  React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化;我们必须通过setState来告知React数据已经发生了变化;

问:在组件中并没有实现setState的方法,为什么可以调用呢?
答:因为setState方法是从Component中继承过来的。

2. setState的三种用法

(1) 基本使用

setState({....})

  this.state = {msg: 'Hello World',counter: 0}...// 点击按钮,调用changeText函数,修改msgchangeText () {this.setState({msg: 'Hello Money'})}

setState里创建了一个新对象赋给state。从内存的角度来看是这样的:
在这里插入图片描述
新对象里没有counter,为什么新对象没有把旧对象覆盖掉呢?
底层其实是用了Object.assign(this.state,setState的新对象),把两个对象做了合并。然后在合适的时机再调用render()渲染。

(2) 传入回调函数

好处一: 可以在回调函数中编写对新state处理的逻辑
好处二: 当前的回调函数会将之前的state和props传递进来

changeText () {this.setState((state, props) => {console.log(state.msg, props) //打印 Hello World,空数组(因为props没值)return {msg: "你好啊, 李银河"}})
}

(3) setState是一个异步调用

changeText () {this.setState({ msg: "你好啊, 李银河" })console.log("------:", this.state.msg) // 打印的是Hello World,而不是新值
}

第三行比第二行先执行,说明setState是一个异步调用。

如果希望在数据更新之后(数据合并), 获取到对应的结果并执行一些逻辑代码
那么可以在setState中传入第二个参数: callback函数

changeText () {this.setState({ msg: "你好啊, 李银河" }, () => {console.log("++++++:", this.state.msg)})console.log("------:", this.state.msg)}

在这里插入图片描述

3. setState为什么要设置成异步

(1) setState设置为异步,可以显著提升性能
如果每次调用setState都进行一次更新,意味着render函数会被频繁调用,界面重新渲染,效率很低;最好的办法是获取到多个更新,之后进行批量更新

 changeCounter () {this.setState((state, props) => {console.log('第一次修改之前', state.count);return {count: state.count + 1}})this.setState((state, props) => {console.log(' 第二次修改之前', state.count);return {count: state.count + 1}})this.setState((state, props) => {console.log('第三次修改之前', state.count);return {count: state.count + 1}})}
render () {console.log('render函数被执行');...
}

三次setState的调用,只调用了一次render函数。
在这里插入图片描述
  如果发送的三个网络请求几乎同时返回结果,修改状态。则此时进行批量更新,只调用一次render,可显著提升性能。

(2) 如果同步更新了state,但未执行render函数,则state和props不能保持同步

state和props不能保持一致性,会在开发中产生很多问题。
在这里插入图片描述
加入18行代码是同步的,调用18行之后,12行的msg内容已变。但此时render函数还未调用,或者没执行完,导致传给子组件的props仍未更新。出现state和props不一致的情况。

二、PureComponent优化性能

1. React的diff算法以及Key的优化(扩展)

(1) diff算法

React的更新流程:

React在props或state发生改变时,会调用React的render方法,进而创建一颗不同的DOM树,然后进行新旧虚拟DOM的对比(diff算法):

 如果新旧两棵虚拟DOM树进行完全比较,(也就是左侧div与右侧的所有节点比较,左侧h2与所有节点进行比较)。则算法的复杂度为O(n^2) (n是树中元素个数)
在这里插入图片描述
React对该算法的优化:

  • 同层节点之间相互比较,不会跨层比较。
    (左侧div只与右侧div进行比较,不会与下一层的h2,button进行比较)
  • 不同类型的节点,产生不同的树结构(后代元素全部做替换)
    (如果左侧的div节点,与右侧同层的节点不一致,则以该节点为根节点的dom树,全部都进行更新,也就是div,h2,button都更换)
  • 开发中,通过key来指定哪些节点在不同的渲染下保持稳定。

(2) 列表中的key属性

和vue一样,key作为一个标识。

  • 当在列表最后位置插入数据时,这种情况,有无key意义并不大

  • 在前面插入数据

    • 在没有key的情况下,所有的li都需要进行修改;
    • 当子元素(这里的li)拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素;
  • key的注意事项
    (1) key应该是唯一的;
    (2) key不要使用随机数(随机数在下一次render时,会重新生成一个数字)
    (3) 使用index作为key,对性能是没有优化的;

2. 引出问题:render函数的优化

现有App、Son1、Son2三个组件

// 只关注render函数
class App extends Component {
...render () {console.log('App render');let { name, age } = this.statereturn (<div><h2>App组件---{name}---{age}</h2><Son1 /><Son2 /><button onClick={() => this.changeName()}>修改名字</button></div>)}
...

在这里插入图片描述
当App修改变量name时,App组件重新调用render函数,而其所有子组件的render函数也被重新调用了。
在这里插入图片描述

只修改App组件数据,所有组件却都需要重新render,重新新旧虚拟DOM对比(diff),性能必然是很低的。

子组件调用render的情况应该是:自己所依赖的数据发生改变时,再调用自己的render方法。

问题 :如何控制render是否被调用呢?

3. shouldComponentUpdate

生命周期函数shouldComponentUpdate(简称SCU)

  • 该函数有两个参数
    参数一:nextProps ,最新的props属性
    参数二:nextState ,最新的state属性

  • 返回值是布尔类型
    返回值为true,调用render方法;
    返回值为false,不调用render方法
    默认返回true

(1) 问题1:如果修改后的值和修改前一样,则不需要调用render函数

// App组件中:shouldComponentUpdate (nextProps, nextState) {if (this.state.name !== nextState.name || this.state.age!== nextState.age) {return true}//nextState.name还是tom,nextState.age还是10,则返回flasereturn false}

(2) 问题2:子组件没用到父组件的数据,则父组件更新时,子组件无需再调用render函数。

现将App中的name传给子组件Son1,age传给子组件Son2

  render () {console.log('App render');let { name, age } = this.statereturn (<div><h2>App组件---{name}---{age}</h2><Son1 name={name} /><Son2 age={age} /><button onClick={() => this.changeName()}>修改名字</button><button onClick={() => this.changeAge()}>修改年龄</button></div>)}

Son1和Son2分别设置SCU
在这里插入图片描述
当点击修改名字时,Son2的render不被调用。修改年龄时,Son1的render不被调用
在这里插入图片描述

4. PureComponent与memo

如果所有的类,都需要手动来实现 shouldComponentUpdate,工作量很多,而且如果需要判断的数据很多,if语句也会很长。

此时我们可以使用React提供的PureComponent 和memo。这两个分别用于类组件和函数式组件

(1) 类组件

对于类组件,继承PureComponent即可,而不是继承Component,
在这里插入图片描述

(2) 函数式组件

函数式组件无法继承,使用memo包裹即可

import { memo } from "react";
const Son3 = memo(function (props) {return (< div ><h3>Son3:{props.age}</h3></div >)
})
export default Son3

5. PureComponent浅层监测

PureComponent的底层是浅层监测数据是否发生变化。

比如在这个页面中,点击添加按钮,需要添加一本书
在这里插入图片描述

   this.state = {books: [{ name: "你不知道JS", price: 99, count: 1 },{ name: "JS高级程序设计", price: 88, count: 1 },{ name: "React高级设计", price: 78, count: 2 },{ name: "Vue高级设计", price: 95, count: 3 },],msg: 'HelloWorld'}
// 添加按钮的回调函数为addNewBook () {const newBook = { name: "Vue高级设计", price: 95, count: 1 }// 方式一:当类组件继承自Component时可以,(虽然可以,但不推荐)// 但继承于Purecomponent时,这种修改方式行不通的this.state.books.push(newBook)this.setState({ books: this.state.books })}

因为books是引用数据类型,它的值是地址值,虽然该数组确实添加了一个元素,但是books地址值未变,所以PureComponent监测不到。
正确打开方式是:

  addNewBook () {const newBook = { name: "Angular高级设计", price: 85, count: 1 }// 方式二: 浅拷贝let books = [...this.state.books]books.push(newBook)this.setState({ books: books })}

在这里插入图片描述
浅拷贝之后的books地址值和this.state.books的地址值不一样(内容一样); 所以 this.setState({ books: books })相当于给state里的books赋值了新值,PureComponent就能监测到了。

6. 实现PureComponent深层检测

如果要修改books里面的count值,也需要进行依次浅拷贝然后再修改。浅拷贝的目的是让books的地址值改变,从而让组件能够监测的到数据变化,调用render函数。

 changeCount (index) {// this.state.books[index] += 1let books = [...this.state.books]books[index].count += 1this.setState({ books: books })}

结合5里画的内存图,其实可以看出第2行与第5行改的是同一块内存。

三、ref获取元素或组件实例

1. ref获取原生DOM的三种方式

方式一:在元素上用ref打标识:<h1 ref='title'>
方式二:调用createRef()函数,先创建一个ref标识,然后再元素上绑定这个标识。
方式三:在标签上通过ref传递一个回调函数,参数值就是当前元素。

import React, { createRef, PureComponent } from 'react'
export class App extends PureComponent {// 获取原生dom的三种方式constructor() {super()// 方式二:先创建一个标识this.hwRef = createRef()// 方式三this.getRef = null}getDOM (el) {// 方式一:被废弃console.log(this.refs.title);// 方式二:.current获取到当前的元素,但是若在很多标签上都标识hwRef,//       .current还是只能获取到一个元素console.log(this.hwRef.current);// 方式三console.log(this.getRef);}render () {return (<div>{/* 方式一: */}<h1 ref='title'>App组件</h1>{/* 方式二:绑定事先创建好的标识 */}<h2 ref={this.hwRef}>HelloWorld</h2>{/* 方式三:这里的el就是dom元素 */}<h3 ref={el => this.getRef = el}>身体健康</h3><button onClick={e => this.getDOM()}>点击获取Dom元素</button></div>)}
}

2. ref获取类组件实例

创建子类Son:

export class Son extends PureComponent {// 实例方法showInfo () {console.log('I am 子组件');}render () {return (<h2>Son组件</h2>)}
}

父类获取到子组件的组件实例后,可以调用子组件的实例方法:

export class App extends PureComponent {constructor() {super()// 1. 创建ref对象this.childRef = createRef()}getDOM () {// 3. 获取子组件实例,并调用子组件的实例方法console.log(this.childRef.current);this.childRef.current.showInfo()}render () {return (<div>{/* 2. 创建的ref对象绑定在子组件上 */}<Son ref={this.childRef} /><button onClick={e => this.getDOM()}>点击获取Dom元素</button></div>)}
}

在这里插入图片描述

2. ref获取函数式组件里的元素

因为函数式组件没有组件实例,上述的方式获取不到函数组件

function Son2 () {return (<h2>Son2组件</h2>)
}<Son2 ref={this.childRef} />
console.log(this.childRef.current); // 打印出来为null

对于函数式组件,我们可以通过ref获取到组件里的某个元素,比如:<h2>Son2组件</h2>
需要借助forwardRef ,这样函数组件可以接收两个参数,一个是props,一个是ref

import React, { createRef, PureComponent, forwardRef } from 'react'
// 这里的ref
const Son2 = forwardRef(function (props, ref) {return (<h2 ref={ref}>Son2组件</h2>)
})

在这里插入图片描述

console.log(this.childRef.current); // <h2>Son2组件</h2>

相关文章:

React(四) 事件总线,setState的原理,PureComponent优化React性能,ref获取类组件与函数组件

文章目录 一、全局事件总线二、setState的原理1. 为什么要使用setState修改数据2. setState的三种用法(1) 基本使用(2) 传入回调函数(3) setState是一个异步调用 3. setState为什么要设置成异步 二、PureComponent优化性能1. React的diff算法以及Key的优化(扩展)(1) diff算法(2…...

Java学习-JVM

目录 1. 基本常识 1.1 JVM是什么 1.2 JVM架构图 1.3 Java技术体系 1.4 Java与JVM的关系 2. 类加载系统 2.1 类加载器种类 2.2 执行顺序 2.3 类加载四个时机 2.4 生命周期 2.5 类加载途径 2.6 双亲委派模型 3. 运行时数据区 3.1 运行时数据区构成 3.2 堆 3.3 栈…...

leed认证分几个级别

LEED&#xff08;Leadership in Energy and Environmental Design&#xff09;认证是一个评估建筑项目可持续性的严格框架&#xff0c;其级别主要分为以下四个&#xff1a; LEED认证&#xff08;Certified&#xff09;&#xff1a;这是最低级别的认证&#xff0c;要求建筑项目…...

3.C++经典实例-计算一个数的阶乘

阶乘&#xff08;factorial&#xff09;是‌基斯顿卡曼于1808年发明的运算符号&#xff0c;用于表示一个正整数n的所有小于及等于该数的正整数的积。自然数n的阶乘写作n!。例如&#xff0c;5的阶乘表示为5! 1 2 3 4 5 120。 阶乘在数学和计算机科学中有广泛的应用。例如…...

深入理解Qt中的QTableView、Model与Delegate机制

文章目录 显示效果QTableViewModel(模型)Delegate(委托)ITEM控件主函数调用项目下载在Qt中,视图(View)、模型(Model)和委托(Delegate)机制是一种非常强大的架构,它们实现了MVC(模型-视图-控制器)设计模式。这种架构分离了数据存储(模型)、数据展示(视图)和数据操作(委托),使…...

解读《ARM Cortex-M3 与Cortex-M4 权威指南》——第1章 ARM Cortex-M处理器简介

1. 三级流水线设计 解释:三级流水线设计意味着处理器在执行指令时可以同时处理多个步骤。这些步骤通常包括取指(Fetch)、译码(Decode)和执行(Execute)。好处:这种设计提高了指令的执行效率,使得处理器能够在每个时钟周期内完成更多的工作,从而提升整体性能。2. 哈佛总…...

java集合类的框架体系

1.集合的好处 相比数组&#xff0c;他可以存储多种类型的元素&#xff0c;并且可以动态新增&#xff1b; 2. 集合分类 3.Collection接口 3.1常用方法 3.2迭代器-遍历 collection接口继承了Interable接口&#xff0c;collection的子类可以使用迭代器&#xff1b; 注意事项…...

基于SpringBoot+Vue+Uniapp家具购物小程序的设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而…...

什么是模糊测试?

近年来&#xff0c;随着信息技术的发展&#xff0c;各种新型自动化测试技术如雨后春笋般出现。其中&#xff0c;模糊测试&#xff08;fuzz testing&#xff09;技术开始受到行业关注&#xff0c;它尤其适用于发现未知的、隐蔽性较强的底层缺陷。这里&#xff0c;我们将结合AFL开…...

3.C++经典实例-奇数还是偶数

要判断一个数是奇数还是偶数&#xff0c;只需要判断这个数是否能被2整除即可&#xff0c;如果要判断是否能整除&#xff0c;则要判断当前数除以2的余数是否为0&#xff0c;在C中&#xff0c;余数&#xff0c;使用%号&#xff0c;因此&#xff0c;程序为&#xff1a; #include …...

真牛啊!全球人工智能标准教科书,斯坦福、麻省理工、加州大学等十多所顶尖机构为它点赞!!

这本《人工智能&#xff1a;计算代理基础》堪称全球人工智能标准教科书&#xff01;它因其前沿的技术融合、丰富的实践案例以及理论深度与实践并重的特点而成为人工智能领域的热门书籍。 该书已经赢得了斯坦福大学、佐治亚理工学院、谷歌大脑、麻省理工学院、加州大学、微软研究…...

Android——通过MediaStore查询图片

查询图片&#xff1a; private void loadImageList() {String[] columns new String[]{MediaStore.Images.Media._ID, // 编号MediaStore.Images.Media.TITLE, // 标题MediaStore.Images.Media.SIZE, // 文件大小MediaStore.Images.Media.DATA, // 文件路径};Cursor cursor g…...

手写Spring IOC-简易版

目录 项目结构entitydaoIUserDaoUserDaoImpl serviceIUserServiceUserServiceImpl ApplicationContext 配置文件初始化 IOC 容器RunApplication 注解初始化 IOC 容器BeanAutowired Reference 项目结构 entity User Data NoArgsConstructor AllArgsConstructor Accessors(chai…...

【算法题】62. 不同路径(LeetCode)

【算法题】62. 不同路径(LeetCode) 1.题目 下方是力扣官方题目的地址 62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图…...

【VUE】Vue中的data属性为什么是一个函数而不是一个对象

在 Vue.js 中&#xff0c;组件的 data 属性可以是一个对象或者一个函数但通常建议将其设置为函数。这是因为组件可能会被多次使用&#xff0c;如果 data 是一个普通对象&#xff0c;那么该对象会被所有实例共享&#xff0c;导致数据混乱。将 data 设置为一个函数可以保证每个组…...

ddos攻击介绍和排查方法

一、DDoS攻击介绍 DDoS攻击&#xff0c;全称为分布式拒绝服务攻击&#xff08;Distributed Denial of Service Attack&#xff09;&#xff0c;是一种常见的网络攻击手段。它通过利用多个计算机系统向目标服务器、服务或网络发送大量请求&#xff0c;导致目标无法处理正常流量…...

git clone --single-branch 提升效率

git clone --single-branch 是一个Git命令&#xff0c;用于从远程仓库中仅克隆单个分支到本地仓库。这个命令在软件开发中非常有用&#xff0c;尤其是在需要特定分支的代码而无需整个仓库的情况下。 基本用法 git clone --single-branch 命令的基本语法如下&#xff1a; git…...

代码随想录算法训练营第十天|1. 两数之和,第454题.四数相加II

文档讲解&#xff1a;代码随想录 难度&#xff1a;一般嗷~~ 1. 两数之和 力扣题目链接(opens new window) 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对…...

龙迅LT8911EX LVDS转EDP 点屏,大批量出货产品

龙迅LT8911EX描述&#xff1a; Lontium LT8911EX是LVDS到eDP转换器&#xff0c;具有单端口或双端口可配置的LVDS接收器&#xff0c;有1个时钟通道和最多8个数据通道&#xff0c;每个数据通道最大运行1.2Gbps&#xff0c;最大输入带宽为9.6Gbps。转换器将输入LVDS数据去序列化&…...

浅谈Oracle之游标

一、基本介绍 在Oracle数据库中&#xff0c;游标&#xff08;Cursor&#xff09;是一种强大的工具&#xff0c;用于逐行处理查询结果集。然而&#xff0c;游标的使用需要谨慎&#xff0c;因为不当的使用可能会导致性能问题。 二、最佳实践和优化技巧 尽量避免使用游标&#xf…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

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

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

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

实战三:开发网页端界面完成黑白视频转为彩色视频

​一、需求描述 设计一个简单的视频上色应用&#xff0c;用户可以通过网页界面上传黑白视频&#xff0c;系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观&#xff0c;不需要了解技术细节。 效果图 ​二、实现思路 总体思路&#xff1a; 用户通过Gradio界面上…...

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...