纯 JS 实现放大缩小拖拽功能(完整代码)
前言
最近团队需要做一个智能客服悬浮窗功能,需要支持拖动、放大缩小等功能,因为这个是全局插件,为了兼容性考虑全部使用原生 JS 实现,不引用任何第三方库或者插件。开发过程中遇到的一些问题及解决方法,在这里和大家分享交流一下。
注下文出现的“采宝”二字,为这个功能的产品名。
先看效果
看这个效果,相信大部分开发都会觉得实现起来比较容易。在实际开发中,笔者了三个主要的坑点,及其解决方案。
三个坑点
- 拖拽采宝时会导致采宝放大缩小
- 采宝显示在屏幕边界时被遮挡显示不全
- 采宝放大和缩小后,位置发生变化
(一)拖拽时会导致采宝放大缩小
我们在操作采宝时,不管是鼠标拖动还是点击放大缩小,我们的事件都需要绑定在采宝头部的图标上,这样我们就需要在图标上绑定点击和拖拽事件。当我们直接添加 click 事件和 mousedown 事件的时候,我们发现在触发 mousedown 事件的时候,也会去触发 click 事件。这样就会出现在拖动采宝的时候,采宝会放大和缩小。
这个效果是我们不想看到的,所以我们就需要区分开采宝上的 click 事件和 mousedown 事件,想办法使两个事件的触发相互不影响。
所以我们在同一个 DIV 上绑定 mousedown 事件和 click 事件,然后通过控制台输出每个事件,查看过程中的每个事件的触发顺序。
const moveBox = document.querySelector('.move'); moveBox.onmousedown = function (evt) { console.log('触发鼠标按下') moveBox.onmousemove = function (evt) { console.log('触发鼠标拖动') } } function moveBoxClick(e) { console.log('触发click') } moveBox.onmouseup = function () { console.log('触发鼠标抬起') }
然后我们得到的结果是
通过控制台的输出情况,我们就可以看到鼠标点击后的各个事件触发情况执行的是 mousedown 事件,然后是 mousemove 事件,再然后是 mouseup 事件,是 click 事件。
知道了事件的触发顺序,我们就可以通过设置一个变量 isMove 来区分开鼠标的拖动事件和点击事件,每次鼠标按下的时候我们将 isMove 复原,鼠标移动的时候将 isMove 的状态改变。
因为每次触发 click 事件的时候也都会去先去触发 mousedown 事件,所以我们在 click 事件里增加一个判断,鼠标移动时,不触发 click 事件。这样就可以把 click 事件和 mousedown 事件区分开来,实现 mousedown 和 click 事件的隔离。
click 事件增加判断
function moveBoxClick(e) { // 点击采宝 const target = document.querySelector(".move"); const smallImg = document.querySelector(".small-img"); const magnifyImg = document.querySelector(".magnify-img"); // 点击move盒子 if (!isMove) { if (isBig) { smallImg.style.display = "block"; magnifyImg.style.display = "none"; target.style.width = "32px"; } else { smallImg.style.display = "none"; magnifyImg.style.display = "block"; target.style.width = "130px"; } isBig = !isBig; } } mousedown 事件重置 isMove 和 mousemove 改变 isMove let isMove = false; // 是否是拖动 let isBig = false; // 是否是变大的盒子 let isMove = false; // 判断是否移动采宝 smallImg.onmousedown = magnifyImg.onmousedown = function(evt) { isMove = false; // 每次鼠标按下时,重置isMove document.onmousemove = function(e) { isMove = true; // 每次鼠标移动时,改变isMove }; };
通过 isMove 的状态,我们就可以区分开 mousemove 事件和 click 事件,使得我们在拖动采宝的时候,可以不去触发采宝放大缩小。
(二)采宝显示在屏幕边界时被遮挡显示不全
我们在拖动采宝时,判断采宝拖动的当前定位坐标是否超出了当前显示屏的高度和宽度,我们需要限制采宝拖动的最大距离。小采宝在点击放大时,也需要做一下处理,把采宝全部显示出来。
拖动时
const moveBox = document.querySelector(".move"); const smallImg = document.querySelector(".move .small-img"); const magnifyImg = document.querySelector(".move .magnify-img"); let isMove = false; // 是否是拖动 let isBig = false; // 是否是变大的盒子 smallImg.onmousedown = magnifyImg.onmousedown = function(evt) { // 拖动div盒子 const clientX = evt.clientX; const clientY = evt.clientY; const pageX = moveBox.offsetLeft; const pageY = moveBox.offsetTop; const x = clientX - pageX; const y = clientY - pageY; document.onmousemove = function(e) { // 拖动后采宝的坐标 let _x = e.clientX - x; let _y = e.clientY - y; const boxWidth = moveBox.offsetWidth; const boxHeight = moveBox.offsetHeight; if (_x < 0) { _x = 0; } // X坐标的最大值 if (_x > window.screen.width - boxWidth) { _x = window.screen.width - boxWidth; } if (_y < 0) { _y = 0; } // Y坐标的最大值 if (_y > document.documentElement.clientHeight - boxHeight) { _y = document.documentElement.clientHeight - boxHeight; } }; }; 小采宝在边界放大时 // 点击时,判断采宝是否超出显示屏 function autoPotion () { let x = moveBox.offsetLeft; let y = moveBox.offsetTop; if (x < 0) { x = 0; } else if (x > document.documentElement.clientWidth - moveBox.offsetWidth) { x = document.documentElement.clientWidth - moveBox.offsetWidth; } if (y < 0) { y = 0; } else if (y > document.documentElement.clientHeight - moveBox.offsetHeight) { y = document.documentElement.clientHeight - moveBox.offsetHeight; } moveBox.style.left = x + "px"; moveBox.style. = y + "px"; }
效果如下
(三)采宝放大和缩小后,位置发生变化
通过上图,我们可以看到,当小采宝处在显示屏边界时,点击放大后再点击缩小,我们发现采宝的位置发生了变化。这个是因为采宝是根据左上角的坐标来定位的,当小采宝移动到右下角时,点击放大以后,采宝左上角的坐标发生了变化,这样就使得采宝在放大缩小时,位置在发生变化。所以,我们在采宝移动完成时需要记录采宝左上角的坐标,在点击时,需要将采宝上次移动完成的坐标重新赋值给采宝,这样就使得采宝在放大缩小时,位置不会发生变化。
这样,我们把每次 mouseup 事件的时候记录下采宝的位置,这样我们解决了采宝放大缩小时位置发生变化的问题。
完整的代码
HTML
<div class="box"> <div class="move"> <img onclick="moveBoxClick()" class="small-img" draggable="false" src="https://zcy-cdn.oss--shanghai.aliyuncs./f2e-assets/103bbf76-6248-421c-a3d6-28a525c459db.png" alt="" /> <img onclick="moveBoxClick()" class="magnify-img" draggable="false" src="https://zcy-cdn.oss--shanghai.aliyuncs./f2e-assets/90e26f49-9824-4443-b4aa-8aa64a3c8690.png" alt="" /> <div class="content"></div> </div> </div> JavaScript const moveBox = document.querySelector(".move"); const smallImg = document.querySelector(".move .small-img"); const magnifyImg = document.querySelector(".move .magnify-img"); var initX = 0; // 记录小采宝的x坐标 var initY = 0; // 记录小采宝的y坐标 let isMove = false; // 是否是拖动 let isBig = false; // 是否是变大的盒子 smallImg.onmousedown = magnifyImg.onmousedown = function(evt) { // 拖动div盒子 const clientX = evt.clientX; const clientY = evt.clientY; const pageX = moveBox.offsetLeft; const pageY = moveBox.offsetTop; const x = clientX - pageX; const y = clientY - pageY; isMove = false; document.onmousemove = function(e) { const boxWidth = moveBox.offsetWidth; const boxHeight = moveBox.offsetHeight; let _x = e.clientX - x; let _y = e.clientY - y; if (_x < 0) { _x = 0; } if (_x > window.screen.width - boxWidth) { _x = window.screen.width - boxWidth; } if (_y < 0) { _y = 0; } if (_y > document.documentElement.clientHeight - boxHeight) { _y = document.documentElement.clientHeight - boxHeight; } if (isBig) { initX = _x; initY = _y; } moveBox.style.left = _x + "px"; moveBox.style. = _y + "px"; isMove = true; }; }; document.onmouseup = function() { if (isMove) { initX = moveBox.offsetLeft; initY = moveBox.offsetTop; } document.onmousemove = null; }; function moveBoxClick(e) { const target = document.querySelector(".move"); const smallImg = document.querySelector(".small-img"); const magnifyImg = document.querySelector(".magnify-img"); // 点击move盒子 if (!isMove) { if (isBig) { smallImg.style.display = "block"; magnifyImg.style.display = "none"; target.style.width = "32px"; target.style.left = initX + 'px'; target.style. = initY + 'px'; } else { smallImg.style.display = "none"; magnifyImg.style.display = "block"; target.style.width = "130px"; } isBig = !isBig; setTimeout(() => { autoPotion(); }, 100) } } // 点击时,判断采宝是否超出显示屏 function autoPotion () { let x = moveBox.offsetLeft; let y = moveBox.offsetTop; if (x < 0) { x = 0; } else if (x > document.documentElement.clientWidth - moveBox.offsetWidth) { x = document.documentElement.clientWidth - moveBox.offsetWidth; } if (y < 0) { y = 0; } else if (y > document.documentElement.clientHeight - moveBox.offsetHeight) { y = document.documentElement.clientHeight - moveBox.offsetHeight; } moveBox.style.left = x + "px"; moveBox.style. = y + "px"; }
以上所述是长沙网络推广给大家介绍的纯 JS 实现放大缩小拖拽功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,长沙网络推广会及时回复大家的。在此也非常感谢大家对狼蚁SEO网站的支持!
如果你觉得本文对你有帮助,欢迎网络推广网站推广转载,烦请注明出处,谢谢!
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程