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

Vue 3 实现高性能拖拽指令的最佳实践

前言

在现代前端开发中,拖拽功能是增强用户体验的重要手段之一。本文将详细介绍如何在 Vue 3 中封装一个拖拽指令(v-draggable),并通过实战例子演示其实现过程。通过这篇教程,您将不仅掌握基础的拖拽功能,还能了解如何优化指令以提升其性能和灵活性,从而为您的项目增色。

封装拖拽指令思路

我们将封装一个简单的拖拽指令,名为 v-draggable,它允许我们在任何元素上添加拖拽功能。
指令逻辑

  1. 监听鼠标事件:我们需要监听 mousedown、mousemove 和 mouseup 事件。
  2. 计算拖动位置:根据鼠标移动的距离更新元素的位置。
  3. 清理事件:在拖动结束后移除事件监听器。

实现步骤

第一步:创建指令文件

在 src 目录下创建一个名为 directives 的文件夹,并在其中创建一个 draggable.js 文件:

// src/directives/draggable.js
export default {mounted(el) {el.style.position = 'absolute';let startX, startY, initialMouseX, initialMouseY;const mousemove = (e) => {const dx = e.clientX - initialMouseX;const dy = e.clientY - initialMouseY;el.style.top = `${startY + dy}px`;el.style.left = `${startX + dx}px`;};const mouseup = () => {document.removeEventListener('mousemove', mousemove);document.removeEventListener('mouseup', mouseup);};el.addEventListener('mousedown', (e) => {startX = el.offsetLeft;startY = el.offsetTop;initialMouseX = e.clientX;initialMouseY = e.clientY;document.addEventListener('mousemove', mousemove);document.addEventListener('mouseup', mouseup);e.preventDefault();});}
};

第二步:注册指令

在 src 目录下的 main.js 文件中注册这个指令:

import { createApp } from 'vue';
import App from './App.vue';
import draggable from './directives/draggable';const app = createApp(App);app.directive('draggable', draggable);app.mount('#app');

第三步:使用指令

现在我们可以在任何组件中使用这个拖拽指令。编辑 src/App.vue 文件:

<template><div><h1>Vue 3 拖拽指令示例</h1><div v-draggable class="draggable-box">拖拽我!</div></div>
</template><script>
export default {name: 'App'
};
</script><style>
.draggable-box {width: 150px;height: 150px;background-color: lightblue;text-align: center;line-height: 150px;cursor: move;user-select: none;
}
</style>

优化拖拽指令

当前的拖拽指令已经可以基本实现拖拽功能了,但还有一些细节需要优化,例如:

  • 限制拖拽范围
  • 支持触摸设备
  • 添加节流来优化性能
  • 提供一些配置选项

限制拖拽范围

我们可以通过对元素的位置进行限制,来防止其被拖出指定的范围。这里我们假定限制在父元素内进行拖拽。

// src/directives/draggable.jsexport default {mounted(el) {el.style.position = 'absolute';let startX, startY, initialMouseX, initialMouseY;const mousemove = (e) => {const dx = e.clientX - initialMouseX;const dy = e.clientY - initialMouseY;let newTop = startY + dy;let newLeft = startX + dx;// 限制拖拽范围在父元素内const parentRect = el.parentElement.getBoundingClientRect();const elRect = el.getBoundingClientRect();if (newLeft < 0) {newLeft = 0;} else if (newLeft + elRect.width > parentRect.width) {newLeft = parentRect.width - elRect.width;}if (newTop < 0) {newTop = 0;} else if (newTop + elRect.height > parentRect.height) {newTop = parentRect.height - elRect.height;}el.style.top = `${newTop}px`;el.style.left = `${newLeft}px`;};const mouseup = () => {document.removeEventListener('mousemove', mousemove);document.removeEventListener('mouseup', mouseup);};el.addEventListener('mousedown', (e) => {startX = el.offsetLeft;startY = el.offsetTop;initialMouseX = e.clientX;initialMouseY = e.clientY;document.addEventListener('mousemove', mousemove);document.addEventListener('mouseup', mouseup);e.preventDefault();});}
};

支持触摸设备

为了支持触摸设备,我们需要添加 touchstart、touchmove 和 touchend 事件监听器。

// src/directives/draggable.jsexport default {mounted(el) {el.style.position = 'absolute';let startX, startY, initialMouseX, initialMouseY;const move = (e) => {let clientX, clientY;if (e.touches) {clientX = e.touches[0].clientX;clientY = e.touches[0].clientY;} else {clientX = e.clientX;clientY = e.clientY;}const dx = clientX - initialMouseX;const dy = clientY - initialMouseY;let newTop = startY + dy;let newLeft = startX + dx;const parentRect = el.parentElement.getBoundingClientRect();const elRect = el.getBoundingClientRect();if (newLeft < 0) {newLeft = 0;} else if (newLeft + elRect.width > parentRect.width) {newLeft = parentRect.width - elRect.width;}if (newTop < 0) {newTop = 0;} else if (newTop + elRect.height > parentRect.height) {newTop = parentRect.height - elRect.height;}el.style.top = `${newTop}px`;el.style.left = `${newLeft}px`;};const up = () => {document.removeEventListener('mousemove', move);document.removeEventListener('mouseup', up);document.removeEventListener('touchmove', move);document.removeEventListener('touchend', up);};const down = (e) => {startX = el.offsetLeft;startY = el.offsetTop;if (e.touches) {initialMouseX = e.touches[0].clientX;initialMouseY = e.touches[0].clientY;} else {initialMouseX = e.clientX;initialMouseY = e.clientY;}document.addEventListener('mousemove', move);document.addEventListener('mouseup', up);document.addEventListener('touchmove', move);document.addEventListener('touchend', up);e.preventDefault();};el.addEventListener('mousedown', down);el.addEventListener('touchstart', down);}
};

添加节流优化性能

为了防止 mousemove 和 touchmove 事件触发得太频繁,我们可以使用节流(throttle)技术来优化性能。

// src/directives/draggable.jsfunction throttle(func, limit) {let lastFunc;let lastRan;return function (...args) {const context = this;if (!lastRan) {func.apply(context, args);lastRan = Date.now();} else {clearTimeout(lastFunc);lastFunc = setTimeout(function () {if (Date.now() - lastRan >= limit) {func.apply(context, args);lastRan = Date.now();}}, limit - (Date.now() - lastRan));}};
}export default {mounted(el) {el.style.position = 'absolute';let startX, startY, initialMouseX, initialMouseY;const move = throttle((e) => {let clientX, clientY;if (e.touches) {clientX = e.touches[0].clientX;clientY = e.touches[0].clientY;} else {clientX = e.clientX;clientY = e.clientY;}const dx = clientX - initialMouseX;const dy = clientY - initialMouseY;let newTop = startY + dy;let newLeft = startX + dx;const parentRect = el.parentElement.getBoundingClientRect();const elRect = el.getBoundingClientRect();if (newLeft < 0) {newLeft = 0;} else if (newLeft + elRect.width > parentRect.width) {newLeft = parentRect.width - elRect.width;}if (newTop < 0) {newTop = 0;} else if (newTop + elRect.height > parentRect.height) {newTop = parentRect.height - elRect.height;}el.style.top = `${newTop}px`;el.style.left = `${newLeft}px`;}, 20);const up = () => {document.removeEventListener('mousemove', move);document.removeEventListener('mouseup', up);document.removeEventListener('touchmove', move);document.removeEventListener('touchend', up);};const down = (e) => {startX = el.offsetLeft;startY = el.offsetTop;if (e.touches) {initialMouseX = e.touches[0].clientX;initialMouseY = e.touches[0].clientY;} else {initialMouseX = e.clientX;initialMouseY = e.clientY;}document.addEventListener('mousemove', move);document.addEventListener('mouseup', up);document.addEventListener('touchmove', move);document.addEventListener('touchend', up);e.preventDefault();};el.addEventListener('mousedown', down);el.addEventListener('touchstart', down);}
};

提供配置选项

最后,我们可以通过指令的参数来提供一些配置选项,例如是否限制在父元素内拖拽。

      const dx = clientX - initialMouseX;const dy = clientY - initialMouseY;let newTop = startY + dy;let newLeft = startX + dx;if (limitToParent) {const parentRect = el.parentElement.getBoundingClientRect();const elRect = el.getBoundingClientRect();if (newLeft < 0) {newLeft = 0;} else if (newLeft + elRect.width > parentRect.width) {newLeft = parentRect.width - elRect.width;}if (newTop < 0) {newTop = 0;} else if (newTop + elRect.height > parentRect.height) {newTop = parentRect.height - elRect.height;}}el.style.top = `${newTop}px`;el.style.left = `${newLeft}px`;}, 20);const up = () => {document.removeEventListener('mousemove', move);document.removeEventListener('mouseup', up);document.removeEventListener('touchmove', move);document.removeEventListener('touchend', up);};const down = (e) => {startX = el.offsetLeft;startY = el.offsetTop;if (e.touches) {initialMouseX = e.touches[0].clientX;initialMouseY = e.touches[0].clientY;} else {initialMouseX = e.clientX;initialMouseY = e.clientY;}document.addEventListener('mousemove', move);document.addEventListener('mouseup', up);document.addEventListener('touchmove', move);document.addEventListener('touchend', up);e.preventDefault();};el.addEventListener('mousedown', down);el.addEventListener('touchstart', down);}
};

使用配置选项

现在我们可以通过在使用指令时传递参数来控制是否限制拖拽范围。例如,编辑 src/App.vue:

<template><div><h1>Vue 3 拖拽指令示例</h1><div v-draggable:limit class="draggable-box">拖拽我!</div><div v-draggable class="draggable-box" style="margin-top: 200px;">我可以拖出容器</div></div>
</template><script>
export default {name: 'App'
};
</script><style>
.draggable-box {width: 150px;height: 150px;background-color: lightblue;text-align: center;line-height: 150px;cursor: move;user-select: none;margin-bottom: 20px;
}
</style>

在上面的例子中,第一个 div 使用了 v-draggable:limit 指令,这意味着它的拖拽范围将被限制在父元素内。而第二个 div 则没有这个限制,可以自由拖动。

总结

通过本文的详细讲解,我们成功实现并优化了一个功能强大的拖拽指令 v-draggable。该指令不仅支持鼠标操作,还兼容触摸设备,并且通过节流机制有效地提升了性能。此外,我们还实现了限制拖拽范围的功能,使得该指令能够适应更多复杂的应用场景。希望本文能帮助您理解和掌握 Vue 3 中自定义指令的封装与优化技巧。

相关文章:

Vue 3 实现高性能拖拽指令的最佳实践

前言 在现代前端开发中&#xff0c;拖拽功能是增强用户体验的重要手段之一。本文将详细介绍如何在 Vue 3 中封装一个拖拽指令&#xff08;v-draggable&#xff09;&#xff0c;并通过实战例子演示其实现过程。通过这篇教程&#xff0c;您将不仅掌握基础的拖拽功能&#xff0c;…...

AIGC--------AIGC在医疗健康领域的潜力

AIGC在医疗健康领域的潜力 引言 AIGC&#xff08;Artificial Intelligence Generated Content&#xff0c;人工智能生成内容&#xff09;是一种通过深度学习和自然语言处理&#xff08;NLP&#xff09;等技术生成内容的方式。近年来&#xff0c;AIGC在医疗健康领域展现出了极…...

Apache Calcite - calcite jdbc驱动使用场景

前言 在使用Calcite查询数据时通常会用到这些代码获取schema Connection connection DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection connection.unwrap(CalciteConnection.class); SchemaPlus rootSchema calciteC…...

IEC61850实现方案和测试-4-MMS协议

IEC61850实现方案和测试-4作为介绍实现方案和测试的第四篇文章&#xff0c;后续会继续更新&#xff0c;欢迎关注。前三篇如下 第一篇是&#xff1a;IEC61850实现方案和测试-1-CSDN博客 第二篇是&#xff1a;IEC61850实现方案和测试-2-UCA-CSDN博客 第三篇是&#xff1a;IEC6…...

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda...

时间的礼物:如何珍视每一刻

《时间的礼物&#xff1a;如何珍视每一刻》 夫时间者&#xff0c;宇宙之精髓&#xff0c;生命之经纬&#xff0c;悄无声息而流转不息&#xff0c;如织锦之细线&#xff0c;串联古今&#xff0c;贯穿万物。 人生短暂&#xff0c;犹如白驹过隙&#xff0c;倏忽而逝&#xff0c;…...

componentReceivePropsreact class生命周期

componentReceiveProps并不是有props的变化触发&#xff0c;而是由父组件的更新触发的 父组件导致组件重新渲染&#xff0c;即使props没有更改&#xff0c;也会调用componentReceiveProps这个方法&#xff1b;如果只想处理更改&#xff0c;确保当前值与变更值比较--官方 …...

快速理解微服务中Sentinel怎么实现限流

Sentinel是通过动态管理限流规则&#xff0c;根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源&#xff1a;在Sentinel中&#xff0c;资源可以是URL、方法等&#xff0c;用于标识需要进行限流的请求&#xff1b;(在Sentinel中&#xff0c;需要我们去告诉Sentinel哪些…...

25.100ASK_T113-PRO 测试摄像头(型号)

1.摄像头 USB2.0 摄像头,支持 UVC协议, 就是V4L2 USB2.0 大概可这样理解吧.这个是2K分辨率. 2.8mm焦距. 开发板还是 100ASK_T113-PRO V1.2版 2.查看摄像头驱动挂载情况 这样接好. 看看设备有没有挂载上 # ls /dev/video* /dev/video0 /dev/video1 这两个就是USB摄像头.说…...

20241127 给typecho文章编辑附件 添加视频 图片预览

Typecho在写文章时&#xff0c;如果一次性上传太多张图片可能分不清哪张&#xff0c;因为附件没有略缩图&#xff0c;无法实时阅览图片&#xff0c;给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…...

StarRocks-join优化

1、背景 有两个大表&#xff0c;都是6kw级别上下的&#xff0c;通过SR然后包装了一个接口对外提供查询&#xff0c;当前的问题是&#xff0c;这样大的join查询会导致BE直接宕机。并且这个sql很有代表性&#xff0c;我截图如下&#xff1a; 这个表是个单分区&#xff0c;所以直接…...

如何通过ChatGPT提高自己的编程水平

在编程学习的过程中&#xff0c;开发者往往会遇到各种各样的技术难题和学习瓶颈。传统的学习方法依赖书籍、教程、视频等&#xff0c;但随着技术的不断发展&#xff0c;AI助手的崛起为编程学习带来了全新的机遇。ChatGPT&#xff0c;作为一种强大的自然语言处理工具&#xff0c…...

实时数据开发 | checkpoints监控和调优

监控Checkpoints 监控 checkpoint 行为最简单的方法是通过 UI 的 checkpoint 部分。 监控这两个指标: 算子收到第一个 checkpoint barrier 的时间。当触发 checkpoint 的耗费时间一直很高时&#xff0c;这意味着 checkpoint barrier 需要很长时间才能从 source 到达 operator…...

面试手撕题积累

1、实现滑动窗口限流&#xff0c;允许每分钟最多有100个请求 阿里一面题。 核心&#xff1a; 时间窗口管理&#xff1a;滑动窗口会根据时间流逝不断更新&#xff0c;需要记录请求的时间戳&#xff0c;并根据当前时间计算窗口内的请求数量。 限流判断&#xff1a;每次请求到来…...

开发中使用UML的流程_05 PIM-1:分析系统流程

目录 1、概述 2、PIM生成的过程 3、用例叙述格式 4、用例关系 5、执行流程&#xff1a; 6、惯用的编号方式 1、概述 在进入到PIM阶段之后&#xff0c;系统分析员将所有系统用例依相关性分成若干组&#xff0c;以组别方式生成该组系统用例涉及的PIM-1---PIM-4产生结果&am…...

【Go】-go中的锁机制

目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS&#xff08;compare and swap&#xff09; 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…...

Scala学习记录,全文单词统计

package test32 import java.io.PrintWriter import scala.io.Source //知识点 // 字符串.split("分隔符"&#xff1a;把字符串用指定的分隔符&#xff0c;拆分成多个部分&#xff0c;保存在数组中) object test {def main(args: Array[String]): Unit {//从文件1.t…...

重构项目架构

前言 我们上篇文章对整个项目进行一个整体的规划&#xff0c;其中对于APP类规划了类&#xff0c;本篇文章我们就来实现这个规划&#xff1b; class App {//加载页面constructor() {}//获取位置_getPosition() {}//接受位置_loadMap() {}//在地图上点击展现表单_showForm() {}/…...

一个开源轻量级的服务器资源监控平台,支持告警推送

大家好&#xff0c;今天给大家分享一款开源的轻量级服务器资源监控工具Beszel&#xff0c;提供历史数据记录、Docker容器统计信息监控以及多种警报功能&#xff0c;用于监控服务器资源。 项目介绍 Beszel由hub&#xff08;中心服务器端应用&#xff0c;基于PocketBase构建&…...

介绍一下atof(arr);(c基础)

hi , I am 36 适合对象c语言初学者 atof(arr)&#xff1b;是返回浮点数(double型)&#xff0c;浮点数数是arr数组中字符中数字 格式 #include<stdio.h> atof(arr); 返回值arr数组中的数 未改变arr数组 #include<stdio.h> //atof(arr) 返 <stdlib> int…...

基于微信小程序的平价药房管理系统+LW参考示例

1.项目介绍 系统角色&#xff1a;管理员、医生、普通用户功能模块&#xff1a;用户管理、医生管理、药品分类管理、药品信息管理、在线问诊管理、生活常识管理、日常提醒管理、过期处理、订单管理等技术选型&#xff1a;SpringBoot&#xff0c;Vue&#xff0c;uniapp等测试环境…...

什么是 C++ 中的函数对象?它有什么特点?如何定义和使用函数对象?数对象与普通函数有什么区别?

在 C 中&#xff0c;函数对象&#xff08;Function Object&#xff09;也被称为仿函数&#xff08;Functor&#xff09;&#xff0c;是一种可以像函数一样被调用的对象&#xff0c;是一个类的对象&#xff0c;该类重载了函数调用运算符operator()。 函数对象的特点: 与普通函数…...

JAVA篇05 —— 内部类(Local、Anonymous、Member、Static)

欢迎来到我的主页&#xff1a;【一只认真写代码的程序猿】 本篇文章收录于专栏【小小爪哇】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 目录 1 内部类Inner Class 1.1 局部内部类 1.2 匿名内部类&#xff08;※※&#xff09; 1.3 匿名类最佳实践&#xf…...

vmware安装ubuntu22.04 复制黏贴 上网

1、ubuntu下载 [Download - 清华镜像站]&#xff1a; 点击 清华大学开源软件镜像站 - Ubuntu 22.04.4 下载 页面中的 ubuntu-22.04.4-desktop-amd64.iso清华大学开源软件镜像站 - Ubuntu 22.04.4 下载 2、安装向导 3、网络设置 sudo netplan try sudo netplan apply4、复制…...

Spring Bean初始化流程

首先&#xff1a; 加载Bean定义(Configuration) 然后对于每个Bean&#xff1a; 1、实例化Bean&#xff08;应该是从Bean方法中获取&#xff0c;Bean方法里面包含new这个类型的代码&#xff09;2、依赖注入&#xff08;所依赖的Bean要经历相同的流程&#xff09;、调用Setter…...

C 语言函数递归探秘:从基础概念到复杂问题求解的进阶之路

我的个人主页 我的专栏&#xff1a;C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 目录 什么是函数递归递归的基本组成递归的工作原理递归的优缺点递归的经典案例 5.1 阶乘计算5.2 斐波那契数列5.3 汉诺塔问题5.4 二分查找 递归的高级…...

【Zookeeper】三,Zookeeper的安装与基本操作

文章目录 安装Zookeeper下载解压解压后的目录结构运行Zookeeper 基本操作 安装Zookeeper 下载 官网下载Zookeeper&#xff0c;会得到一个tar包&#xff0c;如&#xff1a;apache-zookeeper-3.8.4-bin.tar.gz 解压 tar -xvf apache-zookeeper-3.8.4-bin.tar.gz -C /usr/loca…...

STL算法之数值算法<stl_numeric.h>

这一节介绍的算法&#xff0c;统称为数值(numeric)算法。STL规定&#xff0c;欲使用它们&#xff0c;客户端必须包含头文件<numeric>.SGI将它们实现与<stl_numeric.h>文件中。 目录 运用实例 accumulate adjacent_difference inner_product partial_sum pow…...

Git 入门超简单指南

1. 什么是 Git&#xff1f; Git 是一个分布式版本控制系统&#xff0c;由 Linus Torvalds 于 2005 年创建。它的主要目的是帮助开发者有效地管理和跟踪项目的历史版本。通过使用 Git&#xff0c;你可以轻松地记录每一次代码的修改&#xff0c;回滚到以前的版本&#xff0c;以及…...

UE5 和 UE4 中常用的控制台命令总结

调用控制台 按下键盘上的 ~ 键可以调用控制台命令。 技巧 使用键盘的 ↑ 键可以查看之前输入过的指令。控制台指令并不需要打全名&#xff0c;输入空格后跟随指令的部分字符可以进行模糊搜索。按下 Ctrl Shift , 打开 GPUProfile 面板。 命令如下&#xff1a; 调试类 s…...

[护网杯 2018]easy_tornado

这里有一个hint点进去看看&#xff0c;他说md5(cookie_secretmd5(filename))&#xff0c;所以我们需要获得cookie_secret的value 根据题目tornado,它可能是tornado的SSTI 这里吧filehash改为NULL. 是tornado的SSTI 输入{{handler.settings}} (settings 属性是一个字典&am…...

论 ONLYOFFICE:开源办公套件的深度探索

公主请阅 引言第一部分&#xff1a;ONLYOFFICE 的历史背景1.1 开源软件的崛起1.2 ONLYOFFICE 的发展历程 第二部分&#xff1a;ONLYOFFICE 的核心功能2.1 文档处理2.2 电子表格2.3 演示文稿 第三部分&#xff1a;技术架构与兼容性3.1 技术架构3.2 兼容性 第四部分&#xff1a;部…...

华为OD机试真题---幼儿园篮球游戏

华为OD机试真题中的“幼儿园篮球游戏”是一道有趣的逻辑模拟题。以下是该题目的详细描述及解题思路&#xff1a; 题目描述 幼儿园里有一个放倒的圆桶&#xff0c;它是一个线性结构。允许在桶的右边将篮球放入&#xff0c;可以在桶的左边和右边将篮球取出。每个篮球有单独的编…...

C#基础控制台程序

11.有一个54的矩阵&#xff0c;要求编程序求出其中值最大的那个元素的值&#xff0c;以及其所在的行号和列号。 12.从键盘输入一行字符&#xff0c;统计其中有多少个单词&#xff0c;单词之间用空格分隔开。 13.输入一个数&#xff0c;判断它是奇数还是偶数&#xff0c;如果…...

CASS插入多行文字

问题描述 有时在DWG文件中需要标注多行文字&#xff0c;文字注记只是单行的。 解决办法 工具栏中选择文字——>写文字。快捷键是 MTEXT 可以自行换行&#xff0c;并设置相关格式。 当需要把多行文字转换成单行文字的时候&#xff0c;使用下列功能。可以将多行文字变成…...

【青牛科技】D1671 75Ω 带4级低通滤波的单通道视频放大电 路芯片介绍

概 述 &#xff1a; D1671是 一 块 带 4级 低 通 滤 波 的 单 通 道 视 频 放 大 电 路 &#xff0c; 可 在3V或5V的 低 电 压 下 工 作 。 该 电 路 用 在 有 TV影 象 输 出 功 能 的 产 品 上 面&#xff0c;比如 机 顶 盒 &#xff0c;监 控 摄 象 头 &#xff0c;DVD&#…...

基于stm32的智能教室管理系统/智能家居系统

基于stm32的智能教室管理系统/智能家居系统 持续更新&#xff0c;欢迎关注!!! ** 基于stm32的智能教室管理系统/智能家居系统 ** 目前&#xff0c;物联网已广泛应用在我们的生活中。智慧校园是将校园中的生活、学习、工作等相关的资源联系在一起&#xff0c;实现管理的智能化…...

3.10 内核 BUG_ON() at xfs_vm_writepage() -> page_buffers()

目录 前言 问题分析 page buffers创建 page buffers丢失 Write-Protect Dirty Page w/o Buffers 问题解决 前言 这个问题发生在3.10.0-514.el7上&#xff0c;并且在RHEL的知识库中快速找到了对应的案例以及解决方案&#xff0c;但是&#xff0c;理解问题如何发生和解决…...

理解Java集合的基本用法—Collection:List、Set 和 Queue,Map

本博文部分参考 博客 &#xff0c;强烈推荐这篇博客&#xff0c;写得超级全面&#xff01;&#xff01;&#xff01; 图片来源 Java 集合框架 主要包括两种类型的容器&#xff0c;一种是集合&#xff08;Collection&#xff09;&#xff0c;存储一个元素集合&#xff08;单列…...

SQL for XML

关系数据模型与SQL SQL for XML 模式名功能RAW返回的行作为元素&#xff0c;列值作为元素的属性AUTO返回表名对应节点名称的元素&#xff0c;每列的属性作为元素的属性输出输出&#xff0c;可形成简单嵌套结构EXPLICIT通过SELECT语法定义输出XML结构PATH列名或列别名作为XPAT…...

RabbitMQ 篇-深入了解延迟消息、MQ 可靠性(生产者可靠性、MQ 可靠性、消费者可靠性)

??博客主页&#xff1a;【_-CSDN博客】** 感谢大家点赞??收藏评论** 文章目录 ???1.0 RabbitMQ 的可靠性 ? ? ? ? 2.0 发送者的可靠性 ? ? ? ? 2.1 生产者重试机制 ? ? ? ? 2.2 生产者确认机制 ? ? ? ? 2.2.1 开启生产者确认机制 ? ? ? ? 2.2…...

Java设计模式 —— 【创建型模式】原型模式(浅拷贝、深拷贝)详解

文章目录 前言原型模式一、浅拷贝1、案例2、引用数据类型 二、深拷贝1、重写clone()方法2、序列化 总结 前言 先看一下传统的对象克隆方式&#xff1a; 原型类&#xff1a; public class Student {private String name;public Student(String name) {this.name name;}publi…...

LightRAG - 更快更便宜的GraphRAG

检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;已经成为提升大型语言模型&#xff08;LLMs&#xff09;能力的重要方法之一&#xff0c;通过整合外部知识&#xff0c;显著改善了生成内容的质量和相关性。 RAG 的局限性 传统的 RAG 系统虽然表现优…...

基于STM32的智能风扇控制系统

基于STM32的智能风扇控制系统 持续更新&#xff0c;欢迎关注!!! ** 基于STM32的智能风扇控制系统 ** 近几年&#xff0c;我国电风扇市场发展迅速&#xff0c;产品产出持续扩张&#xff0c;国家产业政策鼓励电风扇产业向高技术产品方向发展&#xff0c;国内企业新增投资项目投…...

Java面试问答FAQ

目录&#xff1a; 1、post为什么会发送两次请求&#xff1f;2、单核CPU支持多线程吗&#xff1f;3、ConcurrentHashMap 如何保证线程的安全性&#xff1f; 1、post为什么会发送两次请求&#xff1f; A&#xff1a;那是因为浏览器的安全策略&#xff08;同源策略&#xff09;决…...

PHP中类名加双冒号的作用

在 PHP 中&#xff0c;类名加双冒号&#xff08;::&#xff09; 是一种用于访问类的静态成员和常量的语法。它也可以用来调用类的静态方法和访问 PHP 的类相关关键词&#xff08;如 parent、self 和 static&#xff09;。以下是详细的解释和用法。 1. 用途概述 :: 被称为作用域…...

[极客大挑战 2019]PHP

访问www.zip拿到源码. 绕过这三处. 构造exp <?php class Name{private $username admin;private $password 100;}$select new Name();$resserialize($select); echo $res ?>O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin"…...

【versal】【petalinux】添加LED驱动

versal 添加LED驱动 ` 提示:本文使用外部kernel与uboot`一、LED1.1 LED功能1.2 LED节点1.3 LED操作命令1.3.1 点LED1.3.2 关闭LED二、LED驱动2.1 驱动文件2.2 设备树兼容属性三、 LED设备树配置3.1 设备树配置信息3.2 设备树配置信息讲解四、提示4.1 正确4.2 错误4.3提示:本文…...

【前端】JavaScript中的字面量概念与应用详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;字面量1. 数字字面量2. 字符串字面量3. 布尔字面量4. 空值字面量&#xff08;null&#xff09;5. 对象字面量6. 数组字面量7. 正则表达式字面量8. 特殊值字面量9. 函数字…...

工作学习:切换git账号

概括 最近工作用的git账号下发下来了&#xff0c;需要切换一下使用的账号。因为是第一次弄&#xff0c;不熟悉&#xff0c;现在记录一下。 打开设置 路径–git—git remotes&#xff0c;我这里选择项是Manage Remotes&#xff0c;点进去就可以了。 之后会出现一个输入框&am…...