React js原生 详解 HTML 拖放 API(鼠标拖放功能)

最近碰到了个需求,大概就是要通过可视化拖拽的方式配置一个冰柜,需要把预设好的冰柜内部架子模板一个个拖到冰箱内。一开始的想法是用鼠标事件(mousedown、mouseup等)那一套去实现,能实现但是过程过于复杂,需要控制的状态太多了。其实 Web Api 为 html 元素拖拽量身定制了一套 HTML 拖放API,用这个方法实现一些简单的拖拽功能简直不要太简单。为此写了这篇文章,下面将详细介绍 HTML 拖放 API 的核心知识点

文档

一、被拖拽元素和放置被拖拽元素的元素

通常我们所了解的拖放是按住鼠标左键不放然后移动鼠标把一个页面元素从某个位置移动到另一个位置,然后松开鼠标左键,至此完成了整个拖放过程。在这个过程中我们需要先重点关注两个东西,一个是被拖拽元素另一个是 放置被拖拽元素的元素

1.1 被拖拽元素

我们得先有个概念,页面上显示的元素默认并不都是可以被拖拽的(除了图片、被选中的文字、链接),所以如果当前元素默认不可被拖拽那么就得先把它设置为可拖拽的。ps:可拖拽元素被拖拽时会有一个半透明的快照跟着鼠标移动。

将 HTML 元素的 draggable 属性设置为 true, 元素就可以变为可拖拽元素。效果如下图。

<div id="box" draggable="true">draggable box</div>

在这里插入图片描述

1.2 可放置被拖拽元素的元素

所有的元素区域默认是不支持放置被拖拽元素的,直观的表现是,当被拖拽元素经过不可放置区域时鼠标的样式是一个禁止放置的一个图标(圆圈带一个斜杠),所以需要将目标元素设置为一个可放置区域

默认情况下是这样:

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>

在这里插入图片描述
设置为放置区域需要给元素绑定一个事件 dragover 且要 阻止默认行为

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dropDom = document.getElementById('droppable')dropDom.addEventListener('dragover', (e) => {e.preventDefault()})
</script>

React:
放置区域需要绑定onDragOver事件,且要 阻止默认行为 – 其他事件一样加on

<div draggable="true">draggable box</div>
<div onDragOver={(e) => {e.preventDefault()}}>放置区域</div>

设置为可放置区域后鼠标样式也变了不再是禁止图标,而是一个加号图标(图标可以设置,下面会讲解):
在这里插入图片描述
然而你会发现被拖放元素并没有真正的被放置到放置区域,这是必然的,放置操作需要开发者自行定义,以上的设置只是是为了向用户表明这个区域是允许放东西的,那么至于怎么放需要开发者自行决定。

二、拖拽过程触发的一些事件

这一小节将带你了解整个拖放过程的其他细节,比如拖拽过程中会触发哪些事件

2.1 被拖放目标触发的事件

给被拖放目标元素绑定三个事件 dragstart、drag、dragend。

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dragDom = document.getElementById('box')dragDom.addEventListener('dragstart', (e) => {console.log('开始拖动');})dragDom.addEventListener('drag', (e) => {console.log('拖动中');})dragDom.addEventListener('dragend', (e) => {console.log('结束拖动');})
</script>

React

<div  draggable="true"onDragStart={(e) => {console.log("开始拖动", e);}}onDrag={(e) => {console.log("拖动中", e);}}onDragEnd={(e) => {console.log("结束拖动", e);}}
>
>draggable box</div>
<div onDragOver={(e) => {e.preventDefault()}}>放置区域</div>

开始拖动触发 dragstart ,拖动过程中(鼠标不松开)触发drag,松开鼠标(或者按下 Esc 键)触发 dragend
在这里插入图片描述

2.2 被拖拽元素在放置区域内会触发的事件

先给放置目标元素绑定四个事件

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dropDom = document.getElementById('droppable')dropDom.addEventListener('dragenter', (e) => {console.log('进入到了放置区域~');})dropDom.addEventListener('dragover', (e) => {e.preventDefault()console.log('在放置区域内拖拽中~');})dropDom.addEventListener('dragleave', (e) => {console.log('离开了放置区域~');})dropDom.addEventListener('drop', (e) => {console.log('在放置区域内,放下了被拖拽元素~')})
</script>

拖拽元素进入放置区域内时触发 dragenter 事件,在放置区域内移动被拖放(鼠标不松开)元素触发 dragover 事件,被拖放元素离开放置区域触发 dragleave 事件,在放置区域内松开鼠标触发 drop 事件。
在这里插入图片描述

三、实现真正意义上的元素拖放

通过上面触发的事件我们可以知道,用户真正在放置区域释放鼠标的时候只有 drop 事件能够监听到。所以开发者需要在这个事件里做真正的放置操作,放置什么由开发者决定,可以是被拖拽元素,也可以是自定义的一些内容。

放置被拖拽元素:

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dropDom = document.getElementById('droppable')dropDom.addEventListener('dragover', (e) => {e.preventDefault()console.log('在放置区域内拖拽中~');})dropDom.addEventListener('drop', (e) => {console.log('在放置区域内,放下了被拖拽元素~')e.target.appendChild(document.getElementById('box'))})
</script>

在这里插入图片描述
放置自定义内容

dropDom.addEventListener('drop', (e) => {console.log('在放置区域内,放下了被拖拽元素~')let customCOntent = '<p>自定义内容</p>'e.target.innerHTML = e.target.innerHTML + customCOntent
})

在这里插入图片描述

四、dataTransfer 对象

4.1 从被拖放元素向可放置元素传递数据

dataTransfer 对象提供了一个setData()方法,它接受两个参数,第一个参数是传递数据的类型(一般是标准的MIME类型),第二个数据是数据值。dataTransfer 还提供了 getData() 的方法用于获取传递的数据,它接受一个参数,参数值为 setData 对应的第一个参数。

传递一个简单的字符串数据

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dropDom = document.getElementById('droppable')let dragDom = document.getElementById('box')dragDom.addEventListener('dragstart', (e) => {e.dataTransfer.setData('text/plain', '自定义数据')})dropDom.addEventListener('dragover', (e) => {e.preventDefault()})dropDom.addEventListener('drop', (e) => {let data = e.dataTransfer.getData('text/plain')console.log('你传递的数据为:', data);})
</script>

在这里插入图片描述
⚡注意:只能在 dragstart 事件中设置数据,在其他地方设置无效。且只能在 drop 事件中获取设置的数据,其他事件中获取不到。
案例:根据传递的数据放置不同的内容。

<div id="box" draggable="true">draggable box</div>
<div id="droppable">放置区域</div>
<script>let dropDom = document.getElementById('droppable')let dragDom = document.getElementById('box')dropDom.addEventListener('dragover', (e) => {e.preventDefault()})dropDom.addEventListener('drop', (e) => {let num = e.dataTransfer.getData('num')console.log(num);if(num > 5)e.target.innerHTML = e.target.innerHTML + '<p>传递的数字大于5</p>'else if(num == 5) e.target.innerHTML = e.target.innerHTML + '<p>传递的数字等于5</p>'elsee.target.innerHTML = e.target.innerHTML + '<p>传递的数字小于5</p>'})dragDom.addEventListener('dragstart', (e) => {let num = Math.floor(Math.random() * 10) + 1;e.dataTransfer.setData('num', num)})
</script>

在这里插入图片描述

4.2 自定义拖拽过程中跟随鼠标移动的内容

默认情况下元素被拖拽时会有一个半透明的元素快照跟随着鼠标移动。通过 dataTransfer 提供的 setDragImage(elemnt, xOffset, yOffset) 方法是可以自定义跟随内容。接受三个参数 elemnt 可以是 dom 节点或者一个图片对象,xOffset, yOffset 是相对于鼠标的偏移量。

语法

dataTransfer.setDragImage(img, xOffset, yOffset);

img | Element
用于拖曳反馈图像的图像 Element 元素。

如果 Element 是一个 img 元素,则将拖动位图设置为该元素的图像(保持大小);否则,将拖动数位图设置为从给定元素所生成的图片

xOffset
使用 long 指示相对于图片的横向偏移量

yOffset
使用 long 指示相对于图片的纵向偏移量

解析
  • 发生拖动时,从拖动目标 (dragstart事件触发的元素) 生成半透明图像,并在拖动过程中跟随鼠标指针。这个图片是自动创建的,你不需要自己去创建它。然而,如果想要设置为自定义图像,那么 DataTransfer.setDragImage() 方法就能派上用场。
  • 图像通常是一个 <image> 元素,但也可以是<canvas> 或任何其他图像元素。该方法的 x 和 y 坐标是图像应该相对于鼠标指针出现的偏移量。
    坐标指定鼠标指针相对于图片的偏移量。例如,要使图像居中,请使用图像宽度和高度的一半。通常在 dragstart 事件处理程序中调用此方法。
实际用例

setDragImage 的第一个参数接受的是一个Element参数,这样的话,普通的html元素image元素canvas都可以传递

1、设置为一个图片:

<script>import Tag from "../../style/imgs/attributeTag/路径.png"; //已经存在的图片let dragDom = document.getElementById('box')dragDom.addEventListener('dragstart', (e) => {let img = new Image()// 创建一个图像并且使用它作为拖动图像// 请注意: 改变 "example.gif" 为一个已经存在的图片// 或者,一个还没有创建出来的图片,那么浏览器将会使用默认的拖动图片// 译者注:默认的拖动图片与拖动对象没有联系。一般是一个小型文件图标// 例如:// mg.src = Tag //或// mg.src = `data:image/png;base64,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`;img.src = 'example.gif'e.dataTransfer.setDragImage(img, 10, 10)})
</script>

在这里插入图片描述
2、以官网例子为例,把canvas作为参数传递,我首先尝试的是这种方式,发现并不能生效。(官方的例子没有运行成功)

function dragWithCustomImage(event) {var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");canvas.width = canvas.height = 50;var ctx = canvas.getContext("2d");ctx.lineWidth = 4;ctx.moveTo(0, 0);ctx.lineTo(50, 50);ctx.moveTo(0, 50);ctx.lineTo(50, 0);ctx.stroke();var dt = event.dataTransfer;dt.setData('text/plain', 'Data to Drag');dt.setDragImage(canvas, 25, 25);
}

3、根据案例,我接着使用·HtmlDivElement·作为参数传递,创建了·DIV元素·,此时也·没有生效·。

export function drawDragImage(dataTransfer: DataTransfer, context: string) {
const drawItem: API.EquipmentInfo = JSON.parse(context);
const div = document.createElement(‘div’);
div.style.height = itemObj.height + ‘px’;
div.style.width = itemObj.width + ‘px’;
div.style.border = ‘1px solid #000’;
const span = document.createElement(‘span’);
span.innerText = ‘2222’;
div.appendChild(span);
dataTransfer.setDragImage(div, drawItem.width / 2, drawItem.height / 2);
}

4、然后,我改进了canvas,把canvas转化为图片,第一次拖拽的时候,因为image加载元素是异步导致了没有生效,如图1;第二以后拖拽的时候可以生效,如图二

  const imageContent = canvas.toDataURL('image/jpeg', 1);const image = new Image();image.src = imageContent;image.onload = () => {console.log('image2 load');};dataTransfer.setDragImage(image, drawItem.width / 2, drawItem.height / 2);

在这里插入图片描述

5、最后我尝试了使用官网的方法,同样因为image加载图片是异步的,而拖拽事件是同步发生的,导致了第一次执行失败

function dragstart_handler(ev) {console.log("dragStart");// 设置拖动的格式和数据。使用事件目标的 id 作为数据ev.dataTransfer.setData("text/plain", ev.target.id);// 创建一个图像并且使用它作为拖动图像// 请注意:改变 "example.gif" 为一个已经存在的图片// 或者,一个还没有创建出来的图片,那么浏览器将会使用默认的拖动图片// 译者注:默认的拖动图片与拖动对象没有联系。一般是一个小型文件图标var img = new Image();img.src = 'example.gif';ev.dataTransfer.setDragImage(img, 10, 10);
}
解决方案

在尝试了不同方式设置拖拽反馈图像,总结了一些解决方案

  • 以html页面的元素为模版,动态生成内容,然后设置Element元素参数,可以设置DIV元素的z-index(使用z-index,必须使用position:relative | absolute)–(尝试使用过css1、position:absolute 定位出浏览器可视界面 2、 display:none无用),隐藏在实际页面之下:这样可以动态生成要拖拽的元素,并和生成的fabric的group保持一致。 完美的解决了问题 。
  • 在这里插入图片描述
    js
export function drawDragImage(dataTransfer: DataTransfer, context: string) {const drawItem: API.EquipmentInfo = JSON.parse(context);const dragElement = document.getElementById('dragItem');const idElement = dragElement?.getElementsByClassName('dragItemId')[0];const nameElement = dragElement?.getElementsByClassName('dragItemName')[0];if (idElement) {idElement.innerHTML = drawItem.id;}if (nameElement) {nameElement.innerHTML = drawItem.typeName || '';}if (dragElement) {dragElement.style.height = drawItem.height + 'px';dragElement.style.width = drawItem.width + 'px';dragElement.style.border = '1px solid #000';dragElement.style.background = '#fff';}if (dragElement) {dataTransfer.setDragImage(dragElement, drawItem.width / 2, drawItem.height / 2);}}

React

 import {useRef} from "react";import { Modal, Space, Input, Tree, Button, Badge } from "antd";const mouseStyle = useRef<any>(null);<divdraggable="true"onDragStart={(e) => {//mouseStyle.currente.dataTransfer.setDragImage(mouseStyle.current, 10, 10);}}>移动位置</div>//	
//absolute top-[10%] z-[1] h-10    css使用了tailwindcss
//npm install -D tailwindcss
//https://tailwindcss.com/docs/installation 文档地址<div className="absolute top-[10%] z-[1] h-10" ref={mouseStyle}><Badge count={5}><div className=" border border-[#444444] leading-6 h-6 w-15">2023.09.22初级会计资格考试</div></Badge>
</div>

在这里插入图片描述

4.3 设置放置前的反馈图标

dataTransfer 提供了一个 dropEffect属性设置放置前的反馈图标,它有四种取值 none move copy link

在 dragover 中设置 dropEffect 的值

dropDom.addEventListener('dragover', (e) => {e.preventDefault()e.dataTransfer.dropEffect = 'link' // none || move || copy || link
})
  • 值为 none 或者经过不可放置区域,显示禁止放置图标在这里插入图片描述
  • 值为 move 时
    在这里插入图片描述
  • 值为 copy 时
    在这里插入图片描述
  • 值为 link 时
    在这里插入图片描述

4.4 拖动文件上传

通过 dataTransfer 的 files 属性可以获取用户拖拽的文件信息

拖拽系统文件到放置区域,并打印拖拽的文件信息:

dropDom.addEventListener('drop', (e) => {e.preventDefault()// 上传的文件列表let fileList = e.dataTransfer.filesfor (let i = 0; i < fileList.length; i++) {const file = fileList[i];console.log('文件名:' + file.name);console.log('文件大小:' + file.size);// 后续操作 比如:调接口上传文件}
})

在这里插入图片描述

4.5 清除 setData() 的值

dataTransfer 提供了 clearData() 清除 setData 设置的值,传参数则删除指定类型的值,不传则全部清除。

dropDom.addEventListener('drop', (e) => {console.log(e.dataTransfer.getData('text/plain'));console.log(e.dataTransfer.getData('text/html'));
})dragDom.addEventListener('dragstart', (e) => {e.dataTransfer.setData('text/plain', '自定义数据')e.dataTransfer.setData('text/html', '自定义数据2')e.dataTransfer.clearData('text/html')
})

在这里插入图片描述

4.6 查看设置了哪些类型的值

dataTransfer 提供了 types 属性查看 setData 设置了哪些类型的值。

dropDom.addEventListener('drop', (e) => {console.log(e.dataTransfer.types);
})
dragDom.addEventListener('dragstart', (e) => {e.dataTransfer.setData('text/plain', '自定义数据')e.dataTransfer.setData('text/html', '自定义数据2')
})

在这里插入图片描述

4.7 effectAllowed 属性取值会影响到 dropEffect 的取值效果。

effectAllowed 用于限制 dropEffect 只能设置哪些值

effectAllowed 的取值有: + none -> 此项表示 dropEffect 设置任何值都是禁止效果 + copy -> dropEffect 可以设置为 copy + copyLink -> dropEffect 可以设置为 copy 和 link + copyMove -> dropEffect 可以设置为 copy 和 Move + link -> dropEffect 可以设置为 link + linkMove -> dropEffect 可以设置为 link 和 Move + move -> dropEffect 可以设置为 Move + all -> dropEffect 可以设置为所有合法值 + uninitialized -> 等同 all 效果

dropDom.addEventListener('dragover', (e) => {e.preventDefault()e.dataTransfer.dropEffect = 'move'
})
dragDom.addEventListener('dragstart', (e) => {e.dataTransfer.effectAllowed = 'none'
})

上面即使 dropEffect 设置为 move, 但是 effectAllowed 的值为 none,所有还是禁止放置的反馈图标。
在这里插入图片描述

五、总结

  • 实现一个拖拽功能时先定义好被拖拽元素和放置区域元素。
  • 所有的放置操作都是在 drop 事件中完成。
  • 放置前的反馈效果可以根据你传递的数据来设置 dropEffect 显示不同的效果。
  • 被拖拽元素也可以是放置区域,放置区域也可以是被拖拽元素,两者没有明确的界限。
  • 功能自定义按需求开发

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

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

相关文章

Blender:制作一个变形动画

就是一个球逐渐地变为一个立方体 首先创建一个球和一个立方体 然后把两个物体放在一起&#xff0c;放缩球&#xff0c;让球包含立方体 之后选中球&#xff0c;为其添加修改器&#xff0c;缩裹 在这里选择缩裹对象为立方体 然后在应用下拉箭头中选择“应用为形态键” 下一步选中…

超越平凡:Topaz Photo AI for Mac带您领略人工智能降噪的魅力

在这个充满噪点和高频信息的时代&#xff0c;照片和视频的降噪成为了一个重要而迫切的需求。Mac用户现在有了一个强大的新工具——Topaz Photo AI for Mac&#xff0c;这是一款利用人工智能技术进行降噪和优化的软件。通过这款软件&#xff0c;您可以轻松地改善图像质量&#x…

如何选择高防CDN和高防IP?

目录 前言 一、对高防CDN的选择 1. 加速性能 2. 抗攻击能力 3. 全球覆盖能力 4. 可靠性和稳定性 二、对高防IP的选择 1. 防御能力 2. 服务质量 3. 安全性 4. 价格 三、高防CDN和高防IP的优缺点对比 1. 高防CDN的优缺点 2. 高防IP的优缺点 总结 前言 随着互联网…

翻译docker官方文档(残缺版)

Build with docker(使用 Docker 技术构建应用程序或系统镜像) Overview (概述) 介绍&#xff08;instruction&#xff09; 层次结构&#xff08;Layers&#xff09; The order of Dockerfile instructions matters. A Docker build consists of a series of ordered build ins…

CANdb++数据库操作

CANdb数据库操作 创建工程结构文件夹新建数据库&总线描述节点设置节点创建配置Message属性信号设置节点收发信号 环境变量配置一致性检验数据库工程XVehicle.dbc导入工程文件总结 创建工程结构文件夹 在文件夹X-Vehicle-1下&#xff0c;建立工程目录文件夹CANdb&#xff0…

python 如何获取url的名称

一、使用os模块 os模块是Python内置的一个操作系统接口模块&#xff0c;提供了许多与操作系统相关的函数和变量。其中&#xff0c;os.path模块用于处理路径相关的操作&#xff0c;包括文件名、目录名等。 os.path.basename()函数可以用来获取路径中的文件名部分 imp…

每日一题 136. 只出现一次的数字(简单,位运算)

异或运算性质&#xff0c;两个相等的数作异或运算得零&#xff0c;任何数与零作异或运算保持不变 所以整个数组的异或和就是答案 class Solution:def singleNumber(self, nums: List[int]) -> int:ans 0for i in nums:ans ^ ireturn ans一行代码&#xff0c;reduce作累积操…

数据结构--》连接世界的无限可能—— 图

图作为数据结构中的一种重要概念&#xff0c;扮演着连接世界的纽带。与树和二叉树相比&#xff0c;图更加灵活和多样化&#xff0c;它能够描述各种实际问题中的复杂关系&#xff0c;如社交网络中的人际联系、城市交通中的路线规划以及电子网络中的通信路径等。 无论你是初学者还…

英语学习工具推荐

无论您是初学者还是想要巩固英语能力的学习者&#xff0c;我们都为您提供了一个高效而便捷的英语学习工具。 英语复读机&#xff0c;您可以随时输入您想要复读的英语单词、句子或者文章。我们的复读机会循环播放您输入的内容&#xff0c;帮助您加深记忆、提高听力和口语表达能力…

网络安全—小白学习笔记

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟入…

【数据结构】:二叉树与堆排序的实现

1.树概念及结构(了解) 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的有一个特殊的结点&#…

数据结构之队列

目录 队列的定义与结构 队列的实现 队列的结构 初始化空队列 销毁队列 队尾入队列 队头出队列 获取队列头部元素 获取队列尾部元素 判断队列是否为空 获取队列长度 栈与队列经典试题 队列实现栈 栈实现队列 队列的定义与结构 队列是一种先进先出&#xff08;First…

Netty源码编译

Netty源码编译 想了解Netty源码&#xff0c;最好先从 netty-example 开始&#xff0c;多跑几个 example&#xff0c;了解Netty的实际应用。 编译 netty-example 会出现很多乱七八糟的问题&#xff0c;根本原因是因为缺少 io.netty.util.collection 包。 解决方法 1.先 instal…

指针(2)

1.数组名的理解 一般数组名就是数组首元素的地址 但是有2个例外&#xff1a;1.sizeof&#xff08;数组名&#xff09; 这里面数组名表示的是整个数组&#xff0c;计算整个数组的大小&#xff0c;单位为字节。 …

简单易用,效果卓越的电子期刊制作网站

在日常工作和生活中&#xff0c;我们常常需要制作各种文档和资料&#xff0c;比如电子期刊、宣传册、产品手册等。但有时候&#xff0c;我们会因为排版、设计、编辑等问题而感到烦恼。这时候&#xff0c;一个简单易用、效果卓越的电子期刊制作网站就成为了我们的得力助手&#…

相似性搜索:第 1 部分- kNN 和倒置文件索引

图片来源&#xff1a;维亚切斯拉夫叶菲莫夫 一、说明 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 在数据科学中&#xff0c;相似性搜索经常出现在NLP领域&#xff0c;搜索引擎或推荐系统中&#xff0c;其中需要检索最…

目标文件格式

目标文件里有什么 目标文件格式 目标文件就是源代码编译后但未进行链接的中间文件&#xff08;linux下的.o&#xff09;。 ELF文件&#xff1a;从广义上看&#xff0c;目标文件与可执行文件的格式其实几乎是一样的&#xff0c;可以将目标文件与可执行文件看成是一种类型的文…

忘记开机密码啦!我教你用ventoy找回密码

文章目录 一、前言二、实战过程三、动态演示四、原理解析五、总结 一、前言 当你有一天突然忘记了开机密码怎么办&#xff1f;又要上电脑店花个几十块让人弄&#xff1f;在上一章《你该自己学学安装操作系统了&#xff0c;小白一学就会&#xff08;ventoy装系统超详细&#xff…

Unity设计模式——建造者模式

Product类——产品类&#xff0c;由多个部件组成。 class Product {IList<string> parts new List<string>();//添加产品部件public void Add(string part){parts.Add(part);}public void Show(){foreach (string part in parts){Debug.Log("产品:"pa…

python+深度学习+opencv实现植物识别算法系统 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…