electron+vue3全家桶+vite项目搭建【21】自定义无边框窗口拖拽移动

文章目录

    • 引入
    • 实现思路
    • 实现步骤
      • 1.主进程监听窗口移动
      • 2.通信工具补充ipc调用
      • 3.渲染进程封装通用拖拽组件
    • 测试

引入

如果你尝试过透明窗口,并控制透明部分事件击穿,就会发现使用 drag属性样式去控制窗口拖拽会导致点击事件失效,并且带drag属性的窗口移动到另一个窗口的透明部分会有窗口乱动的各种BUG,于是,这便需要我们自己去实现窗口拖拽移动。

demo项目地址

实现思路

参考这篇文章的实现思路

同网上给出的大多数实现,利用定时器+主进程的screen.getCursorScreenPoint(),在渲染进程开始移动时,让窗口黏在鼠标上,跟随鼠标移动,当停止拖拽时清除主进程的移动定时器。

网上找到的代码有两个常见BUG:

1.windows下,系统设置=>屏幕=>缩放如果设置的不是100% 【测试发现公司60%的非开发人员的缩放都是125%~150%】,会导致拖拽窗口一直放大,如下:

在这里插入图片描述

2.windows【alt+tab】或mac,在进行快捷窗口切换时,如果此时鼠标是按压状态,结束切换会导致窗口一直黏在鼠标上,如下:
在这里插入图片描述

实现步骤

已解决以上所有BUG

1.主进程监听窗口移动

  • electron\main\index.ts
  • 利用定时器实时让当前窗口黏在鼠标上
  • 通过重设窗口宽高,解决windows缩放不是100%时的缩放bug
  • 通过修改位置前判断窗口销毁,来解决窗口被删除,但定时任务未结束,导致报错 调用已销毁窗口的错误
  • 通过判断窗口是否失焦,来解决windows / mac 快捷切换窗口,导致窗口黏在鼠标上的BUG
/** 窗口移动功能封装 */
// 窗口移动 位置刷新定时器
let movingInterval = null;

/**
 * 窗口移动事件
 */
ipcMain.on("window-move-open", (event, canMoving) => {
  let winStartPosition = { x: 0, y: 0 };
  let mouseStartPosition = { x: 0, y: 0 };
  const currentWindow = getWindowByEvent(event);

  const currentWindowSize = currentWindow.getSize();

  if (currentWindow) {
    if (canMoving) {
      // 读取原位置
      const winPosition = currentWindow.getPosition();
      winStartPosition = { x: winPosition[0], y: winPosition[1] };
      // 获取当前鼠标聚焦的窗口
      mouseStartPosition = BrowserWindow.getFocusedWindow();
      // 清除旧的定时器
      if (movingInterval) {
        clearInterval(movingInterval);
      }
      // 创建定时器,每10毫秒更新一次窗口位置,保证一致
      movingInterval = setInterval(() => {
        // 窗口销毁判断,高频率的更新有可能窗口已销毁,定时器还没结束,此时就会出现执行销毁窗口方法的错误
        if (!currentWindow.isDestroyed()) {
          // 如果窗口失去焦点,则停止移动
          if (!currentWindow.isFocused()) {
            clearInterval(movingInterval);
            movingInterval = null;  
          }
          // 实时更新位置
          const cursorPosition = screen.getCursorScreenPoint();
          const x =
            winStartPosition.x + cursorPosition.x - mouseStartPosition.x;
          const y =
            winStartPosition.y + cursorPosition.y - mouseStartPosition.y;
            // 更新位置的同时设置窗口原大小, windows上设置=>显示设置=>文本缩放 不是100%时,窗口会拖拽放大
          currentWindow.setBounds({
            x: x,
            y: y,
            width: currentWindowSize[0],
            height: currentWindowSize[1],
          });
        }
      }, 10);
    } else {
      clearInterval(movingInterval);
      movingInterval = null;
    }
  }
});

2.通信工具补充ipc调用

  • src\utils\electronUtils.ts
/**
* 窗口是否可以跟随鼠标移动
* @param flag
*/
export function windowMove(flag: boolean) {
	ipcRenderer.send("window-move-open", flag);
}

3.渲染进程封装通用拖拽组件

  • src\components\DragTool.vue
<template>
  <div
    @mouseenter="mouseenter"
    @mouseleave="mouseleave"
    @mousedown="mousedown"
    @mouseup="mouseup"
  >
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
import electronUtils from "@/utils/electronUtils";
// 鼠标进入判断,只有鼠标进入到范围内,才能进行鼠标按压拖拽
let enterFlag = false;
// 鼠标按压判断,只有鼠标进入范围内,并且按压状态,此时释放鼠标才会关闭窗口移动
let mousedownFlag = false;

/**鼠标按压 */
function mousedown() {
  if (enterFlag) {
    electronUtils.windowMove(true);
    mousedownFlag = true;
  }
}

/**鼠标释放 */
function mouseup() {
  if (enterFlag && mousedownFlag) {
    electronUtils.windowMove(false);
    mousedownFlag = false;
  }
}

/**鼠标移入 */
function mouseenter() {
  enterFlag = true;
}

/**鼠标移出 */
function mouseleave() {
  enterFlag = false;
}
</script>

<style scoped lang="scss"></style>

测试

直接塞个拖拽盒子

  • src\components\demo\Index.vue
<template>
    <drag-tool>
    <div class="drag-box">拖拽区域</div>
    </drag-tool>
</template>
<style scoped lang="scss">
.drag-box {
  width: 200px;
  height: 50px;
  border: 1px solid #ccc;
  background: pink;
  margin: 0 auto;
  user-select: none;
}
</style>

最终效果如下:

  • 修复前文展示的两个BUG
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

陌陌聊天数据分析 (一)

陌陌聊天数据分析&#xff08;一&#xff09; 目标 基于Hadoop和Hive实现聊天数据统计分析&#xff0c;构建聊天数据分析报表 需求 统计今日总消息量统计今日每小时消息量&#xff0c;发送和接收用户数量统计今日各地区发送消息数据量统计今日发送消息和接收消息用户数统计…

机器学习 day25(softmax在神经网络模型上的应用,提高数据精度的方法)

输出层采用softmax 在识别手写数字的模型中&#xff0c;预测y只有两个结果&#xff0c;所以输出层采用sigmoid激活函数且只有一个神经元。若预测y有10个结果&#xff08;0-9&#xff09;&#xff0c;该模型的前向传播计算方式与识别数字的模型完全相同&#xff0c;即隐藏层的…

符号化的正确姿势

GUI方式 将 .ips crash report 文件拖放到 Xcode > Window > Devices and Simulators > View Device Logs中, 然后导出 .crash 符号化文件. 使用条件: crash report 对应的 Archive 包是在本机构建的 symbolicatecrash symbolicatecrash 是一个 exec (可执行文件), …

Stepper, Slider 的使用

1. Stepper 步进器的使用 1.1 实现 /// 步进器 /加减控件 struct StepperBootcamp: View {State var stepperValue: Int 10State var widthIncrement: CGFloat 0var body: some View {VStack {Stepper("Stepper: \(stepperValue)", value: $stepperValue).padding…

【MATLAB第53期】基于MATLAB的TSK模糊神经网络时间序列预测模型,含短期预测未来功能

【MATLAB第53期】基于MATLAB的TSK模糊神经网络时间序列预测模型&#xff0c;含短期预测未来功能 一、效果展示 二、数据设置 数据采用一列数据滑动窗口设置为5 &#xff0c;可自行设置70%训练30%测试预测未来值为10 &#xff0c;可自行设置&#xff0c;控制10以内 三、模型…

Spring MVC相关注解运用 —— 中篇

目录 一、RESTful风格支持 1.1 RESTful风格介绍 1.2 postman使用 二、PathVariable 2.1 实例程序 2.2 测试结果 三、PostMapping、GetMapping、PutMapping、DeleteMapping 四、HiddenHttpMethodFilter 4.1 在web.xml配置过滤器 4.2 控制器方法 4.3 JSP页面 4.4 测…

论文笔记--SentEval: An Evaluation Toolkit for Universal Sentence Representations

论文笔记--SentEval: An Evaluation Toolkit for Universal Sentence Representations 1. 文章简介2. 文章概括3 文章重点技术3.1 evaluation pipeline3.2 使用 4. 代码4.1 数据下载4.2 句子嵌入4.3 句子嵌入评估 5. 文章亮点6. 原文传送门7. References 1. 文章简介 标题&…

96、基于STM32单片机的温湿度DHT11 烟雾火灾报警器蓝牙物联网APP远程控制设计(程序+原理图+任务书+参考论文+开题报告+流程图+元器件清单等)

单片机及温湿度、烟雾传感器是烟雾报警器系统的两大核心。单片机好比一个桥梁&#xff0c;联系着传感器和报警电路设备。近几年来&#xff0c;单片机已逐步深入应用到工农业生产各部门及人们生活的各个方面。各种类型的单片机也根据社会的需求而开发出来。单片机是器件级计算机…

Redis - 附近商铺、用户签到、UV统计

文章目录 附近商铺、用户签到、UV统计一、附近商铺1.1 GEO数据结构1.2 导入店铺数据到GEO1.3 实现附近商户功能 二、用户签到2.1 BitMap2.2 签到功能2.3 统计连续签到2.3.1 分析2.3.2 代码实现 三、UV统计3.1 HyperLogLog用法3.2 测试百万数据的统计 附近商铺、用户签到、UV统计…

LRU 缓存

题目链接 LRU 缓存 题目描述 注意点 如果插入操作导致关键字数量超过 capacity &#xff0c;则应该 逐出 最久未使用的关键字函数 get 和 put 必须以 O(1) 的平均时间复杂度运行 解答思路 如果想以O(1)的速度进行get&#xff0c;则需要将对应的key、value存到map中如果想…

李子转债上市价格预测

李子转债 基本信息 转债名称&#xff1a;李子转债&#xff0c;评级&#xff1a;AA&#xff0c;发行规模&#xff1a;6.0亿元。 正股名称&#xff1a;李子园&#xff0c;今日收盘价&#xff1a;18.06元&#xff0c;转股价格&#xff1a;19.47元。 当前转股价值 转债面值 / 转股…

RabbitMQ笔记--消息中间件,rabbitmq安装及简单使用

1.消息中间件 消息&#xff1a;指在应用间传送的数据。 消息队列中间件&#xff1a;指利用高效可靠的消息传递机制进行与平台无关的数据交流&#xff0c;并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型&#xff0c;可以在分布式环境下扩展进程间的通…

Elasticsearch【全文检索、倒排索引、应用场景、对比Solr、数据结构】(一)-全面详解(学习总结---从入门到深化)

目录 Elasticsearch介绍_全文检索 Elasticsearch介绍_倒排索引 Elasticsearch介绍_Elasticsearch的出现 Elasticsearch介绍_Elasticsearch应用场景 Elasticsearch介绍_Elasticsearch对比Solr Elasticsearch介绍_Elasticsearch数据结构 Elasticsearch介绍_全文检索 Elasti…

UILabel左上角对齐

设计有个需求&#xff0c;需要文字两行显示&#xff0c;一行的时候左上角对齐&#xff0c;比较常见的需求。 老的办法一般来说是根据宽计算好frame大小&#xff0c;然后重新设置frame。不过感觉这种方式比较麻烦&#xff0c;想了想能不能通过约束来完成这个事情呢。 本着这个思…

(论文翻译)PRUNING FILTER IN FILTER《滤波器中的剪枝滤波器》

公式不清楚的地方请对照英文原文进行查看&#xff1a;原文链接 ABSTRACT 剪枝已成为现代神经网络压缩和加速的一种非常有效的技术。现有的剪枝方法可分为两大类:滤波器剪枝(FP)和权重剪枝(WP)。与WP相比&#xff0c;FP在硬件兼容性方面胜出&#xff0c;但在压缩比方面失败。为了…

springboot开发PC端桌面应用

一、需求描述&#xff1a; 1、要求桌面能在window、Linux和macos系统上运行 2、用户自定义数据筛选策略&#xff0c;策略可通过excel导入导出 3、选择多个excel文件通过策略过滤生成新的excel 二、技术选型及集成环境配置&#xff1a; 1、PC端跨平台直接选用javafx来作为桌…

SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 SpringBoot V…

从零开始制作一个Web蜜罐扫描器(5)

从零开始制作一个Web蜜罐扫描器(3)_luozhonghua2000的博客-CSDN博客 打开一个蜜罐: 查看源码: 这个./js/portraitjs非常引人注入,点进去看一下 很明显是被混淆过了,结合语义来理解,这是portrait=画像,那么可以大胆猜测这段ison是黑客画像用的.猜测了就要进行验证,这里在…

Kafka request.log中RequestQueueTimeMs、LocalTimeMs、RemoteTimeMs、ThrottleTimeMs、含义

Kafka request.log中RequestQueueTimeMs、LocalTimeMs、RemoteTimeMs、ThrottleTimeMs、含义 要理解各个延时项的含义&#xff0c;必须从Kafka收到TCP请求、处理请求到返回TCP包整个流程开始梳理 RequestQueueTimeMs Processor 执行processNewResponses() 方法&#xff0c;不…

软件工程师,学习下JavaScript ES6新特性吧

概述 作为一名软件工程师&#xff0c;不管你是不是前端开发的岗位&#xff0c;工作中或多或少都会用到一点JavaScript。JavaScript是大家所了解的语言名称&#xff0c;但是这个语言名称是Oracle公司注册的商标。JavaScript的正式名称是ECMAScript。1996年11月&#xff0c;JavaS…