React学习02 -事件处理、生命周期和diffing算法

news2024/12/23 22:23:36

文章目录

  • react事件处理
      • 非受控组件
      • 受控组件
      • 高阶函数
      • 函数柯里化
  • 生命周期
      • 引出生命周期
      • 旧版生命周期
      • 新版生命周期
  • Diffing算法

react事件处理

1.react通过onXXX属性指定事件处理函数,
a.react使用的是自定义事件,将原生js事件方法重写并改为小驼峰写法,为了更好的兼容性
b.react中的事件是通过事件委托的方式处理的,在给各个标签添加事件时,其实都是加给最外层标签上;

// 原生js使用事件冒泡,将子标签的事件挂在最外层标签上
<ul id="list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
const list = document.getElementById('list');
list.addEventListener('click', (event)=>{
  if(event.target.tagName === 'LI'){  //通过event.target获取标签元素
    console.log(event.target.textContent);  // 打印点击的元素内容
  }
})

2.react通过event.target得到发生事件的DOM元素对象,不要过度使用ref,当发生事件的元素正好的要操作的元素时,可以不使用ref,达到ref的效果。
在调用方法的时候,传递一个event参数,event.target表示的就是当前元素。

class Demo extends React.Component{
  showData = (event)=>{
    console.log(event.target); // <input type="text" />
    console.log(event.target.value); // 输入框的输入的值
  }
  render(){
    return (
      <input onBlur={this.showData} type="text" />
    )
  }
}

非受控组件

拥有输入性标签,比如输入框、单选框、多选框等元素的组件,且标签的值现取现用(比如下面例子中,输入的用户名与密码点击登录需要使用),这样的组件叫做非受控组件。

// 非受控组件示例
class Login extends React.Component{
  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.username.value, this.password.value);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input ref={(a)=>{this.username=a}} type="text" name="username" />
         <input ref={(a)=>{this.password=a}} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  } // 点击登录后显示用户名与密码,表单提交后默认会跳转页面,所以利用原生事件阻止跳转
}

受控组件

拥有输入性标签,可以将标签的值存储到state里,需要时再拿出来使用的,这样的组件叫做受控组件。

// 受控组件示例
class Login extends React.Component{
  // 初始化状态
  state = {
    username='',
    password=''
  }
  
  saveUsername = (event)=>{
    this.setState(username: event.target.value)
  }

  savePassword = (event)=>{
    this.setState(password: event.target.value)
  }

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={this.saveUsername} type="text" name="username" />
         <input onChange={this.savePassword} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  }  // 使用onCahnge方法,随着标签的值变化,做到state也变化,进而页面也变化,类似vue的双向绑定。
}

建议使用受控组件,可以减少ref的使用。

高阶函数

符合下面两个规范中的任一个的函数,叫做高阶函数。
1.函数接收的参数是一个函数
2.函数返回的是一个函数
常见的高阶函数:Promise, setTimeout, arr.map()得等

// 对象相关的知识,把变量的值作为对象属性的key,要使用[]
let a = 'name';
lei obj = {};
obj.a = 'tom';
console.log(obj); // {a:tom}
obj[a] = 'tom';
console.log(obj); // {a:tom, name:tom}
// 实现只使用一个方法,获取不同的元素值,并存储到state中
class Login extends React.Component{
  // 初始化状态
  state = {
    username='',
    password=''
  }
  
  saveFormData = (key)=>{
    console.log(key);
    return (event)=>{
      console.log(event.target.value);
      // this.setState({key:event.target.value}); //这样会给state添加一个属性,{key:输入的值,username='',password=''}
      this.setState({[key]:event.target.value}); // state={username=输入的值,password=输入的值}
    } // return的这个函数才是onChange真正的回调
  }

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={this.saveFormData('username')} type="text" name="username" />
         <input onChange={this.saveFormData('password')} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  }  // 使用onCahnge方法,{}内应该有一个函数作为onChang方法的回调,加了(),在初始化页面的时候就会调用一次saveFormData方法,默认返回undefined,导致onChange方法失效,所以saveFormData需要返回一个函数,才能保持onChange方法的作用
}

函数柯里化

函数里返回函数,外层函数的参数接收,在最内层函数实现统一处理

// 举例,使用函数柯里化实现三数之和
function sum(a){
  return (b)=>{
    return (c)=>{
      return a+b+c
    }
  }
}
sum(1)(2)(3)  //6
// 比如上面例子中的saveFormData,外层函数接收key,返回的函数接收event,最后在返回的函数中使用key和event处理数据
saveFormData = (key)=>{
    return (event)=>{
      console.log(event.target.value);
      this.setState({[key]:event.target.value});
    } 
}

不使用函数柯里化实现onChange传参

class Login extends React.Component{
  state = {
    username='',
    password=''
  }
  
  saveFormData = (key,event)=>{
      this.setState({[key]:event.target.value}); 
    } 
  

  login = ()=>{
    event.preventDefault(); // 阻止表单提交
    console.log(this.state.username, this.state.password);
  }
  render(){
    return (
      <form onSubmit={this.login}>
         <input onChange={event=>this.saveFormData('username',event)} type="text" name="username" />
         <input onChange={event=>this.saveFormData('password',event)} type="password" name="password" />
         <button>登录</button>
      </form>
    )
  } 
}

生命周期

引出生命周期

概念: 挂载:mount,卸载:unmount
生命周期回调函数(钩子函数):componentDidMount、componentWillUnmount、render…

<div id="test"></div>
class Life ectends React.Component{
  // 移除页面元素
  removeDiv = ()=>{
   // claerInterval(this.timer); // 移除定时器,放在componentWillUnmount方法里等效
    ReactDOM.unmountComponentAtNode(document.getElementById('test')); // 卸载组件
  }
  
  // React在组件挂载完毕时调用
  componentDidMount(){
    // 将定时器挂在组件实例对象上,方便移除组件时可以获取到该定时器
    this.timer = setInterval(()=>{
      let {opacity} = this.state;
      opacity -= 0.1;
      if(opacity<=0) opacity=1;
      this.setState(opacity:opacity);
    },200); // 每0.2秒减少0.1的透明度
  }
  
 // React在组件将要被卸载时调用
 componentWillUnmount(){
   claerInterval(this.timer); // 移除定时器
 }

 // React在初始化渲染、状态更新时调用
  render(){
    return (
      <div>
        <div style={{opacity:this.state.opacity}}>逐渐消失</div>
        <button onClick={this.removeDiv}>点击移除</button>
      </div>
    )
  }
}

旧版生命周期

组件从创建到死亡会经历一些特定阶段,React组件包含一系列钩子函数,会在这些特定阶段调用。钩子函数的调用与定义的顺序无关。

旧版生命周期

图片线路1–挂载渲染页面流程

// 由案例查看各个生命周期钩子--图片左侧路线1相关的钩子
class Count extends React.Component{
  // 构造器
  constructor(props){
    console.log('<Count/> - constructor');
    super(props);
    this.state = {count:0}
  }
  // 组件将要挂载
  componentWillMount(){
    console.log('<Count/> - componentWillMount');
  }
  add = ()=>{
    const count = this.state.count;
    this.setState({count:count+1});
  }
  remove = ()=>{
    ReactDOM.unmounComponentAtNode(document.getElementById('test'));
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <h2>当前求和为:{this.state.count}</h2>
        <button onClick={this.add}>点击+1</button>
        <button onClick={this.remove}>点击卸载组件</button>
      </div>
    )
  }
  // 组件挂载完毕
  componentDidMount(){
    console.log('<Count/> - componentDidMount');
  }
  // 组件将要卸载
  componentWillUnmount(){
    console.log('<Count/> - componentWillUnmount');
  }
}
// 页面加载完成打印顺序constructor->componentWillMount->render->componentDidMount
// 点击卸载组件按钮执行componentWillUnmount钩子

图片线路2–setState流程

class Count extends React.Component{
  state = {count:0}
  add = ()=>{
    const count = this.state.count;
    this.setState({count:count+1});
  }
  remove = ()=>{
    ReactDOM.unmounComponentAtNode(document.getElementById('test'));
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <h2>当前求和为:{this.state.count}</h2>
        <button onClick={this.add}>点击+1</button>
        <button onClick={this.remove}>点击卸载组件</button>
      </div>
    )
  }
 // 组件是否能更新,必须有返回值,返回值为true或false,true允许组件更新,false不允许组件更新,不手动写这个方法时,react默认返回true
  shouldComponentUpdate(){
    console.log('<Count/> - shouldComponentUpdate');
    return true;
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Count/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Count/> - componentDidUpdate');
  }
  // 组件将要卸载
  componentWillUnmount(){
    console.log('<Count/> - componentWillUnmount');
  }
}
// 点击+1按钮,按顺序打印shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
// 点击卸载组件按钮执行componentWillUnmount钩子

图片线路3–forceUpdate流程
forceUpdate用于state没有更新,还需要更新组件的情况

class Count extends React.Component{
  state = {count:0}
  force= ()=>{
    this.forceUpdate();
  }
  // 组件渲染更新
  render(){
    console.log('<Count/> - render');
    return (
      <div>
        <button onClick={this.force}>点击强制更新</button>
      </div>
    )
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Count/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Count/> - componentDidUpdate');
  }
} // 点击强制更新按钮,打印顺序componentWillUpdate->render->componentDidUpdate

图片路线4–父组件render流程
父组件的render流程说的是父组件进行render时,子组件会调用的钩子。
componentWillReceiveProps钩子在组件第一次渲染时不会被调用,之后组件被更新才会被调用

class Father extends React.Component{
  state = {carName:'bmw'}
  changeCar = ()=>{
    this.setState({carName:'bench'})
  }
  render(){
    return (
      <div>
       <h1>父组件</h1>
       <button onClick={this.changeCar}>点击换车</button>
       <Son carName={this.state.carName}/>
      </div>
    )
  }
}
class Son extends React.Component{
  // 组件将要接收参数
  componentWillReceiveProps(){
    console.log('<Son/> - componentWillReceiveProps');
  }
  render(){
    console.log('<Son/> - render');
    return (
       <div>{this.props.carName}</div>
   )
  }
  // 组件是否能更新
  shouldComponentUpdate(){
    console.log('<Son/> - shouldComponentUpdate');
    return true;
  }
  // 组件即将更新
  componentWillUpdate(){
    console.log('<Son/> - componentWillUpdate');
  }
  // 组件完成更新
  componentDidUpdate(){
    console.log('<Son/> - componentDidUpdate');
  }
} // 第一次渲染时,componentWillReceiveProps不执行,打印顺序:render
// 点击按钮,打印顺序:componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
 // 组件将要接收参数,可以接收props参数
  componentWillReceiveProps(props){
    console.log(props); // 按上面的案例,会打印{carName:bench}
  }

总结
一、初始化阶段:由ReactDOM.render()触发,初次渲染
1.constructor()
2.componentWillMount()
3.render()
4.componentDidMount() ===>常用,一般做初始化,比如开定时器、发送网络请求、订阅消息

二、更新阶段:由组件内部this.setState()或父组件render触发
1.shouldComponentUpdate()
2.componentWillUpdate()
3.render() ===> 必须用
4.componentDidUpdate()
三、卸载组件:由ReactDOM.unmountComponentAtNode()触发
1.componentWillUnmount() ===>常用,一般做收尾,比如关闭定时器、取消订阅

新版生命周期

新版本react(16.x以上)将以下三个函数添加了“UNSAFE_”前缀,因为这些生命周期钩子经常被误用滥用,react推出异步渲染后可能会持续误用滥用,导致出现bug。未来这些钩子可能被弃用。

componentWillMount ==> UNSAFE_componentWillMount
componentWillReceiveProps ==> UNSAFE_componentWillReceiveProps
componentWillUpdate ==> UNSAFE_componentWillUpdate

新版生命周期

对比新旧生命周期图:
在挂载时,新版本取消了componentWillMount,换成了getDrivedStateFormProps,其他的没变。
在更新时,新版本取消了componentWillReceiveProps,换成了getDrivedStateFormProps,取消了componentWillUpdate,新增了getSnapshotBeforeUpdate。
总结,取消了三个Will钩子,新增了getDrivedStateFormProps和getSnapshotBeforeUpdate两个钩子。

getDrivedStateFormProps在render前调用,作为静态方法挂在实例上,且需要返回一个state对象或null。

static getDrivedStateFormProps(){
  return null;
} // return null时,不影响state及页面初始化和更新
static getDrivedStateFormProps(){
  return {key:value};
} // return 一个对象时,会将这个对象赋给state,同时更新页面
// 当getDrivedStateFormProps返回一个对象时,初始化和更新后的状态都会按照返回的这个对象去渲染
class Count extends React.Component{
  state = {count:0}
  add = ()=>{
    this.setState(count:this.state.count+1)
  } // 点击按钮后,count显示999
  static getDrivedStateFormProps(){
    return {count:999};
  } // 初始化页面时,count显示999
  render(){
    return (
      <div>
        <h1>count: {this.state.count}</h1>
        <button onClick={this.add}>点击+1</button>
      </div>
    )
  }
}

getDrivedStateFormProps可以接收两个参数,第一个为props,第二个为state。

static getDrivedStateFormProps(props,state){
  return 对象/null;
}

若state的值在任何时候都取决于props,可以使用getDrivedStateFormProps方法。

static getDrivedStateFormProps(props,state){
   // ...各种操作
  return props;
}

getSnapshotBeforeUpdate方法在最近一次渲染提交到DOM之前调用,接收两个参数,第一个为更新前的props,第二个为更新前的state,必须返回一个拍照值或者null,返回的值会作为参数传给componentDidUpdate钩子。

getSnapshotBeforeUpdate(preProps,preState){
  return 拍照值/null;
}
// componentDidUpdate接收三个参数,更新前的props,更新前的state,拍照值
componentDidUpdate(preProps,preState,snapshotValue){}
class Count extends React.Component{
  state = {count:0}
  add = ()=>{
    this.setState(count:this.state.count+1)
  } 
  componentDidUpdate(preProps,preState,snapshotValue){
    console.log(preProps,preState,snapshotValue);
  } // 点击按钮,打印{},{count:0},shotvalue
  getSnapshotBeforeUpdate(preProps,preState){
    return 'shotvalue';
  }
  render(){
    return (
      <div>
        <h1>count: {this.state.count}</h1>
        <button onClick={this.add}>点击+1</button>
      </div>
    )
  }
}

getSnapshotBeforeUpdate可以在组件发生变化之前从DOM获取信息,可以用来处理滚动位置,比如滚动位置的聊天线程。
总结
一、初始化阶段:由ReactDOM.render()触发,初次渲染
1.constructor()
2.getDrivedStateFormProps()
3.render()
4.componentDidMount() ===>常用,一般做初始化,比如开定时器、发送网络请求、订阅消息

二、更新阶段:由组件内部this.setState()或父组件render触发
1.getDrivedStateFormProps()
2.shouldComponentUpdate()
3.render() ===> 必须用
4.getSnapshotBeforeUpdate()
5.componentDidUpdate()
三、卸载组件:由ReactDOM.unmountComponentAtNode()触发
1.componentWillUnmount() ===>常用,一般做收尾,比如关闭定时器、取消订阅

Diffing算法

diffing算法是react使用render时,遍历每一个元素,做到只更新变化了的元素的一种算法。

// 每秒钟更新span标签里的内容,在输入框内输入内容,可以看到两个输入框不会被更新
state = {date:new Date()}
componentDidMount(){
  setInterval(()=>{
    this.setState({
      date:new Date()
    })
  },1000)
}
render(){
  return (
    <div>
      <input type="text"/>
      <span>
        当前时间:{this.state.date.toTimeString()}
        <input type="text"/>
      </span>
    </div>
  )
}  

经典面试题:react中的key有什么作用?key的内部原理是什么?
key是虚拟DOM的标识,在diff算法里有重要作用。
当状态发生变化时,react会根据新数据生成新虚拟DOM,然后进行新旧虚拟DOM的diff比较。
在旧虚拟DOM里找新虚拟DOM相同的key:
1.没找到,根据新数据创建新DOM,渲染到页面;
2.找到了,对比DOM里的内容是否相同:
a. 内容相同,使用旧虚拟DOM生成的真实DOM;
b. 内容不同,根据新数据创建新DOM,替换原来的真实DOM,渲染到页面;

经典面试题:为什么遍历列表时,key最好不要用index?
使用index作为key,可能会引发的问题:
1.对数据进行破坏顺序的操作,如逆序添加、逆序删除等操作,会产生没有必要的真实DOM更新,页面显示无问题,效率低;
2.如果结构里包含输入类的DOM,会产生错误DOM更新,页面会显示错乱;
3.如果不存在对数据进行破坏顺序的操作,使用Index作为key是没有问题的。

注意,对比的是每一个标签元素,嵌套的标签元素中,若里层元素没有变,外层元素变了,更新的只有外层元素。

class Person extends React.Component{
  state = {
    person:[
      {id:'p1',name:'tom',age:'19'}
      {id:'p2',name:'jery',age:'20'}
    ]
  }
  add = ()=>{
    const {person} = this.state;
    const p = {id:'p3',name:'pety',age:'20'}
    this.setState({person:[p,...person]}); // 将新元素新增到状态数组的最前面
  }
  render(){
    return (
      <div>
        <button onClick={this.add}>点击+</button>
        <ul id="ul1">
          this.state.person.map((p,index)=>{
            return <li key={index}>{p.name}---{p.age} <input type="text"/></li>
          })
        </ul>
        <ul id="ul2">
          this.state.person.map((p)=>{
            return <li key={p.id}>{p.name}---{p.age} <input type="text"/></li>
          })
        </ul>
      </div>
    )
  }
}
/** 页面初始化后,在输入框输入一样的内容,两个列表分别显示以下内容:
 1.id="ul1"               2.id="ul2"
 tom---19   tom---19       tom---19  tom---19
 jery---20  jery---20      jery---20 jery---20  
点击按钮,两个ul分别呈现以下状况:
 1.id="ul1"               2.id="ul2"
 pety---20 tom---19		   pety---20
 tom---19  jery---20       tom---19  tom---19
 jery---20                 jery---20 jery---20  
 可以看到以index为key的,当新增数组元素在数组最前面,数组所有元素的下标都发生了改变,遍历生成虚拟DOM时,新旧虚拟DOM对比可以找到key相同的元素,但是内容已经发生了变化,所以所有li元素都重新生成真实DOM更新渲染了;但li里面的input元素经过对比后发现没有更新,所以使用原来的真实DOM,导致页面出现错位的现象。
 **/

开发中如何选择key?
最好选择数据中的唯一标识作为key,如id, 手机号,身份证号等唯一标识。
如果只是简单展示数据,数据不会进行乱序处理,使用index也是可以的。

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

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

相关文章

大数据新视界 --大数据大厂之大数据驱动下的物流供应链优化:实时追踪与智能调配

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

前端自定义指令控制权限(后端Spring Security)

1. 新建 directives/auth.ts &#xfeff; &#xfeff; //导入自定义指令 import auth from /directives/auth// 注册全局自定义指令 v-auth app.directive(auth, auth);&#xfeff;1.1完整的authDirective.ts import { wmsStore } from "/store/pinia"// 判断用…

dmdfm5安装部署

dmdfm5安装部署 1 环境说明2 命令行安装dmfdm52.1 创建 dmdba 用户2.2 命令行安装 dmdfm2.3 配置自启动脚本服务2.4 web端 访问 dmdfm 3 安装过程错误记录4 更多达梦数据库学习使用列表 1 环境说明 cpu x86OS 麒麟v10(sp2)dmfdm5 版本 : dmdfm_V5.0.1.1_rev157137_x86_linux_6…

计算机网络803-(4)网络层

目录 1.虚电路服务 虚电路是逻辑连接 2.数据报服务 3.虚电路服务与数据报服务的对比 二.虚拟互连网络-IP网 1.网络通信问题 2.中间设备 3.网络互连使用路由器 三.分类的 IP 地址 1. IP 地址及其表示方法 2.IP 地址的编址方法 3.分类 IP 地址 &#xff08;1&#x…

双通讯直流电能计量装置功能介绍

DJSF1352系列电子式直流电能表是为满足现代直流电力计量需求而设计的高性能设备。其主要特点包括液晶显示和RS485通讯功能&#xff0c;方便与微机进行数据交互&#xff0c;适用于充电桩、蓄电池、太阳能电池板等多种直流信号设备的电量监测。该产品由测量单元、数据处理单元、通…

python数学运算库numpy的使用

数组 numpy创建数组的方法 可以用np.array()将一个列表作为参数 import numpy as npd1 np.array(range(1,7))print(d1) # 输出数据 print(d1.size) # 输出元素个数 print(d1.ndim) # 输出数组维度 print(d1.shape) # 输出数组形状&#xff08;长宽高&#xff09; 可以…

pdf合并成一个文件,揭秘四款好用软件!

在这个数字化时代&#xff0c;PDF文件已成为我们工作、学习和生活中不可或缺的一部分。无论是报告、合同、还是学术论文&#xff0c;PDF以其跨平台兼容性和良好的格式保持性赢得了广泛青睐。然而&#xff0c;面对多个PDF文件需要合并成一个完整文档时&#xff0c;你是否也曾感到…

对于JS脚本加标签功能的一些小理解

在JS中加标签&#xff0c;最主要的应用场景就是结合循环代码使用。用标签标识循环或者代码块&#xff0c;以便使用break 和 continue语句来结束循环。个人觉得标签加循环的本质作用是为了增加性能&#xff0c;减少运行代码行&#xff0c;以便提速。示例如下&#xff1a; 打印输…

Leetcode.20 有效的括号

关键词&#xff1a;vector, push_back(), pop_back(), stack, push(), pop(), top() 1.题目 2.解答思路及解答 解答思路&#xff1a; 左括号需要一个相同的括号&#xff0c;如果是括号嵌套的方式&#xff0c;可以类比“回文数”那题&#xff0c;利用双下标或者双指针遍历。 …

shell 脚本批量更新本地git仓库

文章目录 一、问题概述二、解决方法三、运行效果1. windows2. centos 一、问题概述 你是否遇到这样的场景&#xff1a; 本地git仓库克隆了线上的多个项目&#xff0c;需要更新时&#xff0c;无法象svn一样&#xff0c;选中多个项目一起更新。 只能苦逼的一个个选中&#xff0c…

【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem

git clone 是 Git 版本控制系统中的一个基本命令&#xff0c;用于从远程仓库复制一个完整的版本库到本地。这个命令不仅复制远程仓库中的所有文件&#xff0c;还复制仓库的历史记录&#xff0c;使得你可以在本地进行版本控制操作&#xff0c;如提交&#xff08;commit&#xff…

YOLO11改进|SPPF篇|引入YOLOv9提出的SPPELAN模块

目录 一、【SPPELAN】模块1.1【SPPELAN】模块介绍1.2【SPPELAN】核心代码 二、添加【SPPELAN】模块2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【SPPELAN】模块 1.1【SPPELAN】模块介绍 下图是【SPPELAN】的结构图&#xff0c;让我们…

AI产品经理面试100问,三天看完一周拿5个offer

Attention(重点掌握) 1.什么是 Attention?为什么要用 Attention?它有什么作用? 2.Attention的流程是什么样的? 3.普通的Attention和Transformer的Self-attention之间有什么关系? 4.什么是Self-attention? Transformer(重点掌握) 1.Transformer是什么&#xff0c;它的基…

socket编程(java)

socket编程&#xff08;java&#xff09; 简介 ​ Socket&#xff08;套接字&#xff09;是计算机网络编程中用于实现网络通信的一种机制。它提供了一种编程接口&#xff0c;允许应用程序通过网络进行数据传输&#xff0c;实现不同主机之间的通信。 ​ Socket可以看作是一种…

多态相关问题

多态 1、概念的概念 通俗来讲&#xff0c;就是多种形态。具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 例子&#xff1a;新用户 领红包 99 老用户 领红包 2 不常用 领红包 6 符合多态条件&#xff1a; #include <iostream> using …

计算机毕业设计 医院预约挂号系统的设计与实现 Python毕业设计 Python毕业设计选题【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

力扣之1364.顾客的可信联系人数量

题目&#xff1a; sql建表语句&#xff1a; Create table If Not Exists Customers (customer_id int, customer_name varchar(20), email varchar(30)); Create table If Not Exists Contacts (user_id int, contact_name varchar(20), contact_email varchar(30)); Cre…

qiankun 主项目和子项目都是 vue2,部署在不同的服务器上,nginx 配置

1、主项目配置 1.1 micro.vue 组件 <template><div id"container-sub-app"></div> </template><script> import { loadMicroApp } from qiankun; import actions from /utils/actions.js;export default {name: microApp,mixins: [ac…

react实现实时计时的最简方式

js中时间的处理&#xff0c;不借助于moment/dayjs这样的工具库&#xff0c;原生获取格式化的时间&#xff0c;最简单的实现方式可以参考下面这样。 实现效果 代码实现 封装hooks import { useState, useEffect } from "react";export function useCountTime() {c…

Linux——which-find命令

which命令 查找命令的程序文件&#xff08;二进制 find命令 按文件名查找文件 find / -name "test" 命令 路径(根目录 命令选项 查找文件名 find命令 -name 模糊查询 find / -name "…