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

【React系列】react-router

本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MDAzNzkwNA==&action=getalbum&album_id=1566025152667107329)

一. 认识react-router

1.2. 前端路由原理

前端路由是如何做到URL和内容进行映射呢?监听URL的改变。

URL 的 hash

  • URLhash也就是锚点(#), 本质上是改变window.locationhref属性;
  • 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新;
<div id="app"><a href="#/home">home</a><a href="#/about">about</a><div class="router-view"></div>
</div><script>// 1.获取router-viewconst routerViewEl = document.querySelector(".router-view");// 2.监听hashchangewindow.addEventListener("hashchange", () => {switch(location.hash) {case "#/home":routerViewEl.innerHTML = "home";break;case "#/about":routerViewEl.innerHTML = "about";break;default:routerViewEl.innerHTML = "default";}})
</script>

hash的优势就是兼容性更好,在老版IE中都可以运行,但是缺陷是有一个#,显得不像一个真实的路径。

HTML5 的 History

history接口是 HTML5 新增的, 它有六种模式改变URL而不刷新页面:

  • replaceState:替换原来的路径;
  • pushState:使用新的路径;
  • popState:路径的回退;
  • go:向前或向后改变路径;
  • forword:向前改变路径;
  • back:向后改变路径;

我们这里来简单演示几个方法:

<div id="app"><a href="/home">home</a><a href="/about">about</a><div class="router-view"></div>
</div><script>// 1.获取router-viewconst routerViewEl = document.querySelector(".router-view");// 2.监听所有的a元素const aEls = document.getElementsByTagName("a");for (let aEl of aEls) {aEl.addEventListener("click", (e) => {e.preventDefault();const href = aEl.getAttribute("href");console.log(href);history.pushState({}, "", href);historyChange();})}// 3.监听popstate和go操作window.addEventListener("popstate", historyChange);window.addEventListener("go", historyChange);// 4.执行设置页面操作function historyChange() {switch(location.pathname) {case "/home":routerViewEl.innerHTML = "home";break;case "/about":routerViewEl.innerHTML = "about";break;default:routerViewEl.innerHTML = "default";}}</script>

1.3. react-router

目前前端流行的三大框架, 都有自己的路由实现:

  • Angular的ngRouter
  • React的ReactRouter
  • Vue的vue-router

React Router的版本4开始,路由不再集中在一个包中进行管理了:

  • react-router是router的核心部分代码;
  • react-router-dom是用于浏览器的;
  • react-router-native是用于原生应用的;

目前我们使用最新的React Router版本是v5的版本:

  • 实际上v4的版本和v5的版本差异并不大;

安装react-router:

yarn add react-router-dom
  • 安装react-router-dom会自动帮助我们安装react-router的依赖;

二. react-router基本使用

2.1. Router基本使用

react-router最主要的API是给我们提供的一些组件:

  • BrowserRouter或HashRouter
    • Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件;
    • BrowserRouter使用history模式;
    • HashRouter使用hash模式;
  • Link和NavLink:
    • 通常路径的跳转是使用Link组件,最终会被渲染成a元素;
    • NavLink是在Link基础之上增加了一些样式属性(后续学习);
    • to属性:Link中最重要的属性,用于设置跳转到的路径;
  • Route:
    • Route用于路径的匹配;
    • path属性:用于设置匹配到的路径;
    • component属性:设置匹配到路径后,渲染的组件;
    • exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件;

在App中进行如下演练:

import React, { PureComponent } from 'react';import { BrowserRouter, Route, Link } from 'react-router-dom';import Home from './pages/home';
import About from './pages/about';
import Profile from './pages/profile';export default class App extends PureComponent {render() {return (<BrowserRouter><Link to="/">首页</Link><Link to="/about">关于</Link><Link to="/profile">我的</Link><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route path="/profile" component={Profile} /></BrowserRouter>)}
}

在这里插入图片描述

2.2. NavLink的使用

路径选中时,对应的a元素变为红色

这个时候,我们要使用NavLink组件来替代Link组件:

  • activeStyle:活跃时(匹配时)的样式;
  • activeClassName:活跃时添加的class;
  • exact:是否精准匹配;

先演示activeStyle

<NavLink to="/" activeStyle={{color: "red"}}>首页</NavLink>
<NavLink to="/about" activeStyle={{color: "red"}}>关于</NavLink>
<NavLink to="/profile" activeStyle={{color: "red"}}>我的</NavLink>

但是,我们会发现在选中aboutprofile时,第一个也会变成红色:

  • 原因是/路径也匹配到了/about/profile
  • 这个时候,我们可以在第一个NavLink中添加上exact属性;
<NavLink exact to="/" activeStyle={{color: "red"}}>首页</NavLink>

默认的activeClassName

  • 事实上在默认匹配成功时,NavLink就会添加上一个动态的active class
  • 所以我们也可以直接编写样式
a.active {color: red;
}

当然,如果你担心这个class在其他地方被使用了,出现样式的层叠,也可以自定义class

<NavLink exact to="/" activeClassName="link-active">首页</NavLink>
<NavLink to="/about" activeClassName="link-active">关于</NavLink>
<NavLink to="/profile" activeClassName="link-active">我的</NavLink>

在这里插入图片描述

2.3. Switch的作用

我们来看下面的路由规则:

<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/profile" component={Profile} />
<Route path="/:userid" component={User}/>
<Route component={NoMatch}/>
  • 当我们匹配到某一个路径时,我们会发现有一些问题;
  • 比如/about路径匹配到的同时,/:userid也被匹配到了,并且最后的一个NoMatch组件总是被匹配到;
    在这里插入图片描述

原因是什么呢?默认情况下,react-router中只要是路径被匹配到的Route对应的组件都会被渲染;

但是实际开发中,我们往往希望有一种排他的思想:

  • 只要匹配到了第一个,那么后面的就不应该继续匹配了;
  • 这个时候我们可以使用Switch来将所有的Route进行包裹即可;
<Switch><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route path="/profile" component={Profile} /><Route path="/:userid" component={User} /><Route component={NoMatch} />
</Switch>

2.3. Redirect的使用

Redirect用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中:

我们这里使用这个的一个案例:

  • 用户跳转到User界面;
  • 但是在User界面有一个isLogin用于记录用户是否登录:
    • true:那么显示用户的名称;
    • false:直接重定向到登录界面;

App.js中提前定义好Login页面对应的Route

<Switch>...其他Route<Route path="/login" component={Login} /><Route component={NoMatch} />
</Switch>

User.js中写上对应的逻辑代码:

import React, { PureComponent } from 'react'
import { Redirect } from 'react-router-dom';export default class User extends PureComponent {constructor(props) {super(props);this.state = {isLogin: false}}render() {return this.state.isLogin ? (<div><h2>User</h2><h2>用户名: coderwhy</h2></div>): <Redirect to="/login"/>}
}

三. react-router高级使用

3.1. 路由嵌套

在开发中,路由之间是存在嵌套关系的。

这里我们假设about页面中有两个页面内容:

  • 商品列表和消息列表;
  • 点击不同的链接可以跳转到不同的地方,显示不同的内容;
import React, { PureComponent } from 'react';import { Route, Switch, Link } from 'react-router-dom';function AboutProduct(props) {return (<ul><li>商品列表1</li><li>商品列表2</li><li>商品列表3</li></ul>)
}function AboutMessage(props) {return (<ul><li>消息列表1</li><li>消息列表2</li><li>消息列表3</li></ul>)
}export default class About extends PureComponent {render() {return (<div><Link to="/about">商品</Link><Link to="/about/message">消息</Link><Switch><Route exact path="/about" component={AboutProduct} /><Route path="/about/message" component={AboutMessage} /></Switch></div>)}
}

3.2. 手动跳转

目前我们实现的跳转主要是通过Link或者NavLink进行跳转的,实际上我们也可以通过JavaScript代码进行跳转。

但是通过JavaScript代码进行跳转有一个前提:必须获取到history对象。

如何可以获取到history的对象呢?两种方式

  • 方式一:如果该组件是通过路由直接跳转过来的,那么可以直接获取history、location、match对象;
  • 方式二:如果该组件是一个普通渲染的组件,那么不可以直接获取history、location、match对象;

那么如果普通的组件也希望获取对应的对象属性应该怎么做呢?

  • 前面我们学习过高阶组件,可以在组件中添加想要的属性;
  • react-router也是通过高阶组件为我们的组件添加相关的属性的;

如果我们希望在App组件中获取到history对象,必须满足以下两个条件:

  • App组件必须包裹在Router组件之内;
  • App组件使用withRouter高阶组件包裹;

index.js代码修改如下:

ReactDOM.render(<BrowserRouter><App /></BrowserRouter>,document.getElementById('root')
);

App.js代码修改如下:

import { Route, Switch, NavLink, withRouter } from 'react-router-dom';
...省略其他的导入代码class App extends PureComponent {render() {console.log(this.props.history);return (<div>...其他代码<button onClick={e => this.pushToProfile()}>我的</button><Switch><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route path="/profile" component={Profile} /><Route path="/:userid" component={User} /><Route component={NoMatch} /></Switch></div>)}pushToProfile() {this.props.history.push("/profile");}
}export default withRouter(App);

源码选读:这里的 history 来自哪里呢?是否和之前使用的 window.history 一样呢?

我们发现withRouter的高阶函数来自react-router-dom

实际上来自react-router的包;

在这里插入图片描述

withRouter函数:

在这里插入图片描述

history对象来自哪里呢?

  • 实际来自上面代码的context
    在这里插入图片描述

这个context的值来自哪里呢?

  • 来自于context.Consumervalue中;

在这里插入图片描述

this.props.history来自哪里呢?

  • 来自BrowserRouter或者HashRouter在创建时,传入的值;
  • 又传递给了RouterRouter的子组件可以通过该context获取到这个值;

在这里插入图片描述

createBrowserHistory来自哪里呢?

在这里插入图片描述

执行push操作的本质:

在这里插入图片描述

3.3 传递参数

传递参数有三种方式:

  • 动态路由的方式;
  • search传递参数;
  • to传入对象;

动态路由的方式

动态路由的概念指的是路由中的路径并不会固定:

  • 比如/detailpath对应一个组件Detail
  • 如果我们将pathRoute匹配时写成/detail/:id,那么 /detail/abc/detail/123都可以匹配到该Route,并且进行显示;
  • 这个匹配规则,我们就称之为动态路由;

通常情况下,使用动态路由可以为路由传递参数。

<div>...其他Link<NavLink to="/detail/abc123">详情</NavLink><Switch>... 其他Route<Route path="/detail/:id" component={Detail}/><Route component={NoMatch} /></Switch>
</div>

detail.js的代码如下:

import React, { PureComponent } from 'react'export default class Detail extends PureComponent {render() {console.log(this.props.match.params.id);return (<div><h2>Detail: {this.props.match.params.id}</h2></div>)}
}
  • 我们可以直接通过match对象中获取id
  • 这里我们没有使用withRouter,原因是因为Detail本身就是通过路由进行的跳转;

search传递参数

NavLink写法:

<NavLink to="/detail2?name=why&age=18">详情2</NavLink><Switch><Route path="/detail2" component={Detail2}/>
</Switch>
  • 我们在跳转的路径中添加了一些query参数;

Detail2中如何获取呢?

  • Detail2中是需要在location中获取search的;
  • 注意:这个search没有被解析,需要我们自己来解析;
import React, { PureComponent } from 'react'export default class Detail2 extends PureComponent {render() {console.log(this.props.location.search); // ?name=why&age=18return (<div><h2>Detail2:</h2></div>)}
}

to传入对象

to可以直接传入一个对象

<NavLink to={{pathname: "/detail2", query: {name: "kobe", age: 30},state: {height: 1.98, address: "洛杉矶"},search: "?apikey=123"}}>详情2
</NavLink>

获取参数:

import React, { PureComponent } from 'react'export default class Detail2 extends PureComponent {render() {console.log(this.props.location);return (<div><h2>Detail2:</h2></div>)}
}

在这里插入图片描述

补充:使用 history.push 如何传递参数

在React中如何使用history.push传递参数主要有三种方式:

第一种如下:

this.props.history.push{pathname:'/router/url/send',query:{'oneFlag':one,}}

接收情况如下:

this.props.location.query.oneFlag

其路由路径显示:

'#/router/url/send?oneFlag=one'

第二种情况如下:

this.props.history.push{pathname:'/router/url/send',state:{'oneFlag':one,}
}

接收情况如下:

this.props.location.state.oneFlag // one

其路由显示:

'#/router/url/send'

第三种情况需要在配置路由时,将路由配置为rest格式路由,

  {path: '/device/detail/:id',component: DeviceDetail,pageConfig: {title: '设备详情',auth: ['admin'],},},

传递参数时:

<Button text type="primary" onClick={() => history.push({ pathname: `/device/detail/${record.id}` })}>详情
</Button>

参数接收时:

 const { id } = props.match.params;

第一种和第三种,在目标路由刷新后,参数还可以取到,但是第二种页面刷新后,参数就取不到了,第二种适合开发winform类的应用。

第一种和三种在使用时要注意监听参数的变化,不然路由回退,再次进图另外参数的页面,组件不会重新渲染,用hook组件开发的话,需要用useEffect来监听参数变化。

四. react-router-config

目前我们所有的路由定义都是直接使用Route组件,并且添加属性来完成的。

但是这样的方式会让路由变得非常混乱,我们希望将所有的路由配置放到一个地方进行集中管理:

  • 这个时候可以使用react-router-config来完成;

安装react-router-config

yarn add react-router-config

常见router/index.js文件:

import Home from "../pages/home";
import About, { AboutMessage, AboutProduct } from "../pages/about";
import Profile from "../pages/profile";
import Login from "../pages/login";
import User from "../pages/user";
import Detail from "../pages/detail";
import Detail2 from "../pages/detail2";
import NoMatch from "../pages/nomatch";const routes = [{path: "/",exact: true,component: Home},{path: "/about",component: About,routes: [{path: "/about",exact: true,component: AboutProduct},{path: "/about/message",component: AboutMessage},]},{path: "/profile",component: Profile},{path: "/login",component: Login},{path: "/user",component: User},{path: "/detail/:id",component: Detail},{path: "/detail2",component: Detail2},{component: NoMatch}
];export default routes;

将之前的Switch配置,换成react-router-config中提供的renderRoutes函数:

{renderRoutes(routes)}{/* <Switch><Route exact path="/" component={Home} /><Route path="/about" component={About} /><Route path="/profile" component={Profile} /><Route path="/user" component={User} /><Route path="/login" component={Login} /><Route path="/detail/:id" component={Detail}/><Route path="/detail2" component={Detail2}/><Route component={NoMatch} /></Switch> */}

如果是子组件中,需要路由跳转,那么需要在子组件中使用renderRoutes函数:

  • 在跳转到的路由组件中会多一个 this.props.route 属性;
  • route属性代表当前跳转到的路由对象,可以通过该属性获取到 routes
export default class About extends PureComponent {render() {return (<div><Link to="/about">商品</Link><Link to="/about/message">消息</Link>{renderRoutes(this.props.route.routes)}</div>)}
}

实际上react-router-config中还提供了一个matchRoutes辅助函数:

  • matchRoutes(routes, pathname)传入一个路由对象数组,获取所有匹配的路径;
const routes = matchRoutes(this.props.route.routes, "/about");
console.log(routes);

查看renderRoutes的源码也是非常简单的:

在这里插入图片描述

相关文章:

【React系列】react-router

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. 认识react-router 1.2. 前端路由原理 前端路由是如何做到URL和内容进行映射呢&#xff1f;监听URL的改变。 UR…...

[数据集][目标检测]车辆检测数据集VOC+YOLO格式1.6w张3类别

一共分为3个压缩包&#xff1a; 【车辆检测数据集AVOCYOLO格式5423张3类别】 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5423 标注数…...

FindMy技术用于鼠标

鼠标是计算机的标准配置之一&#xff0c;其设计初衷是为了使计算机的操作更加简便快捷&#xff0c;减少用户在操作中的负担。用户可以通过移动鼠标&#xff0c;实现光标的精确移动&#xff0c;进而选择、拖拽、复制、粘贴等操作。这种操作方式&#xff0c;使得计算机的操作变得…...

已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题

已解决‘ping‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。”的问题 文章目录 问题介绍 问题分析 解决思路 解决方法 检查并修复环境变量 进入c:\windows\system32再ping 使用系统工具修复系统文件 Q1 - 问题介绍 当您尝试在Windows命令提示符下…...

基于PGPGPOOL-II部署PostgreSQL高可用环境

PGPOOL-II是一个位于PostgreSQL服务器和 PostgreSQL 数据库客户端之间的中间件,具有以下功能: 1. 连接池:PGPOOL-II可以保持已经连接到 PostgreSQL 服务器的连接,并在使用相同参数(例如:用户名、数据库、协议版本)连接进来时重用它们。这可以减少连接开销,并增加系统的…...

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 概述-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行模式-CSDN博客 1、模板虚拟机环境准备 1.1、 hadoop100 虚拟机配置要求如下 &…...

Python 操作 JMeter 探索:pymeter 实操指南

概要 JMeter 是一个流行的性能测试工具&#xff0c;用于测试 Web 应用程序的性能和负载。它通常与 GUI 一起使用&#xff0c;但如果您想在自动化测试中集成 JMeter&#xff0c;或者以编程方式创建和运行测试计划&#xff0c;那么 pymeter 库将是一个强大的工具。本文将介绍如何…...

微软 Power Platform 使用Power Automate发送邮件以Dataverse作为数据源的附件File Column

微软Power Platform使用Power Automate发送邮件添加Power Apps以Dataverse作为数据源的附件File Column方式 目录 微软Power Platform使用Power Automate发送邮件添加Power Apps以Dataverse作为数据源的附件File Column方式1、需求背景介绍2、附件列File Column介绍3、如何在Po…...

雾天条件下 SLS 融合网络的三维目标检测

论文地址&#xff1a;3D Object Detection with SLS-Fusion Network in Foggy Weather Conditions 论文代码&#xff1a;https://github.com/maiminh1996/SLS-Fusion 论文摘要 摄像头或激光雷达&#xff08;光检测和测距&#xff09;等传感器的作用对于自动驾驶汽车的环境意识…...

在pycharm中执行 os.makedirs 提示用户名或密码不正确

问题&#xff1a;在pycharm中运行脚本&#xff0c;在 \10.0.21.249\share 共享目录下创建目录提示错误 发现&#xff1a;手动在该目录下创建目录没有问题。 解决方法&#xff1a; 切换到cmd 命令行运行该脚本成功创建 猜测&#xff1a;感觉应该是pycharm中使用的用户名和密码存…...

使用Go语言编写高效的HTTP服务器

随着互联网的快速发展&#xff0c;HTTP服务器在Web开发中扮演着越来越重要的角色。而Go语言作为一种高效、并发性强的编程语言&#xff0c;为编写高性能的HTTP服务器提供了强大的支持。本文将探讨如何使用Go语言编写高效的HTTP服务器。 首先&#xff0c;我们需要了解Go语言的H…...

代码随想录day20 开始二叉搜索树

654.最大二叉树 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…...

从0开始python学习-39.requsts库

目录 HTTP协议 1. 请求 2. 响应 Requests库 1. 安装 2. 请求方式 2.1 requests.请求方式(参数) 2.2 requests.request() 2.3 requests.session().request() 2.4 三种方式之间的关联 3. 请求参数 3.1 params&#xff1a;查询字符串参数 3.2 data&#xff1a;Form表单…...

【面试高频算法解析】算法练习3 双指针

前言 本专栏旨在通过分类学习算法&#xff0c;使您能够牢固掌握不同算法的理论要点。通过策略性地练习精选的经典题目&#xff0c;帮助您深度理解每种算法&#xff0c;避免出现刷了很多算法题&#xff0c;还是一知半解的状态 专栏导航 二分查找回溯双指针滑动窗口深度优先搜索…...

React16源码: Why16, 研究源码的意义, 源码目录核心结构分析

为什么要选择React16 现在React18都早已实践很多&#xff0c;为何回过头来看16版本的代码理由如下 从实际出发&#xff0c;企业内老旧项目多为16版本&#xff0c;理解16的核心能够帮助我们快速解决问题16版本React是完全重写了核心代码, 是一次重大的更新 引入了 fiber 这个概…...

mybatis-flex笔记

MyBatis-Flex 的增删改功能 - MyBatis-Flex 官方网站https://mybatis-flex.com/zh/base/add-delete-update.html 代码https://gitee.com/hntianshu/mybatis-flex-test 一 新增数据 不忽略 null 值。 就是允许有null 忽略null 就是不允许有null BaseMapper 的接口提供了 inser…...

Debezium发布历史47

原文地址&#xff1a; https://debezium.io/blog/2019/02/13/debezium-0-9-1-final-released/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Debezium 0.9.1.Final 发布 二月 13, 2019 作者&#xff1a; Gunna…...

Python爬虫抓包常见问题解决

对于Python爬虫和Fiddler抓包&#xff0c;可能遇到的问题及解决&#xff1a; 代理设置错误&#xff1a;如果你在使用Python爬虫时遇到抓不到包的问题&#xff0c;首先应该检查你的浏览器代理设置是否正确。以Chrome为例&#xff0c;代理设置为&#xff1a;右上角菜单按钮>设…...

c++跨平台ui

fltk https://gitee.com/mirrors_fltk/fltk.git codeblock中有fltk项目开发模板,可以快速构建项目 wxwidget https://gitee.com/sofu456/wxWidgets.git git submodule update --init --recursive 打开demo和sample set(wxBUILD_SAMPLES ALL) set(wxBUILD_DEMOS ON) build/…...

stable diffusion 基础教程-提示词之艺术风格用法

展现夕阳 golden hour, (rim lighting):1.2, warm tones, sun flare, soft shadows, vibrant colors, hazy glow, painterly effect, dreamy atmosphere阴影 chiaroscuro, (high contrast):1.2, dramatic shadows, bold highlights, moody atmosphere, captivating inte…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

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

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

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...