基于javascript的拖拽类封装详解


Posted in Javascript onApril 19, 2019

效果图如下

基于javascript的拖拽类封装详解

github地址如下: github地址

使用方法

引入js和对应的css

import Drag from '../../static/dragger.js'
import './assets/css/dragger.css'

之后,实例化

new Drag({
  id: 'box-dragger',
  showAngle: true,
  isScale: false,
  showBorder: false
})
new Drag({
  id: 'box-dragger2',
  canZoom: false,
  canRotate: false
})
new Drag({
  id: 'img-box',
  showAngle: true,
  showPosition: true
  })
new Drag({
  id: 'test'
})

具体实现(封装细节)

功能细节整理:

  1. 旋转
  2. 缩放
  3. 平移

技术难点:

  1. 旋转时要注意盒子每一个点的位置发生了变化
  2. 针对拖拽后的盒子的left和top都有变化,计算其left和top时需将其按照中心轴旋转摆正,再进行计算
  3. 当且仅有一个盒子是被选中的盒子,点击哪个选中哪个。(当前页面多个实例化Drag对象时,如何保证操作互不影响)
  4. 实现的两种不同方式:

可以选中某元素,直接给该元素内部加上操作的点
有一个pannel,选中某元素时,将这个pannel定位到该元素的位置上

这两种方式都实现过一次,第一种比较简单,但是第一种,不好控制选中某个元素才让操作点展示。

如何封装:

考虑如何让用户快速上手使用,可参考的点:

  1. 用户需要传入什么必须的参数
  2. 暴露给用户什么可设置的参数和方法

实现过程:

可配置参数

字段 说明 是否必填 默认值
id 目标元素id
container 父容器id body
canRotate 是否可以旋转 true
canZoom 是否可以缩放 true
canPull 是否可以拉升 true
canMove 是否可以平移 true
showAngle 展示角度 false
showPosition 展示位置 false
isScale 是否等比例缩放 true
showBorder 是否展示pannel的border false

属性

  1. canRotate
  2. canZoom
  3. canPull
  4. canMove
  5. showAngle
  6. isScale
  7. id
  8. container
  9. targetObj
  10. pannelDom 操作divdom
  11. ...

具体看图:

基于javascript的拖拽类封装详解

代码解说

初始化参数

初始化目标dom对象的位置:记录其:

  1. left平距左
  2. top
  3. width
  4. height
  5. angle
  6. rightBottomPoint 目标dom对象右下坐标
  7. rightTopPoint 目标dom对象右上坐标
  8. leftTopPoint 目标dom对象左上坐标
  9. leftBottomPoint 目标dom对象左下坐标
  10. leftMiddlePoint 目标dom对象左中坐标
  11. rightMiddlePoint 目标dom对象右中坐标
  12. topMiddlePoint 目标dom对象上中坐标
  13. bottomMiddlePoint 目标dom对象下中坐标
  14. centerPos 目标dom对象中心点坐标

初始化pannel结构

当前的父容器中只有一个pannel结构,每次实例化对象时,会判断一下如果当前这个父容器里已经存在id为pannel的结构,就将其子节点清空,按照当前实例化对象传进来的属性重新渲染pannel子结构。如果没有id为pannel的结构,就创建。

初始化事件

  1. 给pannelDom和targetObj绑定mousedown事件
  2. 给document绑定mousemove和mouseup事件

 

initEvent () {
  document.addEventListener('mousemove', e => {
    e.preventDefault && e.preventDefault()
    this.moveChange(e, this.targetObj)
  })
  document.addEventListener('mouseup', e => {
    this.moveLeave(this.targetObj)
  })
  if (this.canMove) {
    // 外层给this.pannelDom添加mousedown事件,是在所有实例化结束后,panneldom被展示在最后一个实例化对象上,鼠标按下它时,触发moveInit事件
    this.pannelDom.onmousedown = e => {
      e.stopPropagation()
      this.moveInit(9, e, this.targetObj)
    }
    this.targetObj.onmousedown = e => {
      e.stopPropagation()
      this.moveInit(9, e, this.targetObj)
      this.initPannel()
      // 在点击其他未被选中元素时,pannel定位到该元素上,重写pannelDom事件,因为此时的this.pannelDom已经根据新的目标元素被重写
      this.pannelDom.onmousedown= e => {
        this.moveInit(9, e, this.targetObj)
      }
    }
  }
}

dom操作

旋转操作

鼠标按下时,记录当前鼠标位置距离box中心位置的y/x的反正切函数A1。 

this.mouseInit = {
  x: Math.floor(e.clientX),
  y: Math.floor(e.clientY)
}
this.preRadian = Math.atan2(this.mouseInit.y - this.centerPos.y, this.mouseInit.x - this.centerPos.x)

鼠标移动时,记录再次计算鼠标位置距离box中心位置的y/x的反正切函数A2。

this.rotateCurrent = {
  x: Math.floor(e.clientX),
  y: Math.floor(e.clientY)
}
this.curRadian = Math.atan2(this.rotateCurrent.y - this.centerPos.y, this.rotateCurrent.x - this.centerPos.x)

求A2-A1,求出移动的弧度

this.tranformRadian = this.curRadian - this.preRadian

求出最后box的旋转角度,this.getRotate(target)是js中获取某dom元素的旋转角度的方法(粘贴过来的,亲测好使)

this.angle = this.getRotate(target) + Math.round(this.tranformRadian * 180 / Math.PI)
this.preRadian = this.curRadian //鼠标移动的每一下都计算这个角度,所以每一下移动前的弧度值都上一次移动后的弧度值

计算旋转后box每个点的坐标,根据余弦公式,传入:旋转前每点坐标,旋转中心坐标和旋转角度

let disAngle = this.angle - this.initAngle
this.rightBottomPoint = this.getRotatedPoint(this.initRightBottomPoint, this.centerPos, disAngle)
this.rightTopPoint = this.getRotatedPoint(this.initRightTopPoint, this.centerPos, disAngle)
this.leftTopPoint = this.getRotatedPoint(this.initLeftTopPoint, this.centerPos, disAngle)
this.leftBottomPoint = this.getRotatedPoint(this.initLeftBottomPoint, this.centerPos, disAngle)
this.leftMiddlePoint = this.getRotatedPoint(this.initLeftMiddlePoint, this.centerPos, disAngle)
this.rightMiddlePoint = this.getRotatedPoint(this.initRightMiddlePoint, this.centerPos, disAngle)
this.topMiddlePoint = this.getRotatedPoint(this.initTopMiddlePoint, this.centerPos, disAngle)
this.bottomMiddlePoint = this.getRotatedPoint(this.initBottomMiddlePoint, this.centerPos, disAngle)

沿着一个方向拉升操作。

沿着一个角缩放操作。 这两个操作,主要参考了一个大佬的拖拽思想实现的 github wiki地址

优化,mousemove事件添加节流函数

function throttle(fn, interval) {
  let canRun = true;
  return function () {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      canRun = true;
    }, interval);
  };
}
let that = this
document.addEventListener('mousemove', throttle(function (e) {
  e.preventDefault && e.preventDefault()
  that.moveChange(e, that.targetObj)
}, 10))

以上所述是小编给大家介绍的基于javascript的拖拽类封装详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript模拟的Ping效果代码 (Web Ping)
Mar 13 Javascript
jQuery实现鼠标移到元素上动态提示消息框效果
Oct 20 Javascript
js 判断文件类型并控制表单提交示例代码
Nov 14 Javascript
jquery实现网页的页面平滑滚动效果代码
Nov 02 Javascript
jquery动态增加删减表格行特效
Nov 20 Javascript
通过扫描二维码打开app的实现代码
Nov 10 Javascript
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
Mar 23 jQuery
使用clipboard.js实现复制功能的示例代码
Oct 16 Javascript
浅谈angularJS2中的界面跳转方法
Aug 31 Javascript
node实现socket链接与GPRS进行通信的方法
May 20 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
Jun 10 Javascript
关于layui 实现点击按钮添加一行(方法渲染创建的table)
Sep 29 Javascript
Bootstarp在pycharm中的安装及简单的使用方法
Apr 19 #Javascript
Vue Cli 3项目使用融云IM实现聊天功能的方法
Apr 19 #Javascript
详解vue-cli+es6引入es5写的js(两种方法)
Apr 19 #Javascript
vue中使用vue-cli接入融云实现即时通信
Apr 19 #Javascript
浅谈Javascript中的对象和继承
Apr 19 #Javascript
详解如何在Vue项目中导出Excel
Apr 19 #Javascript
vue cli使用融云实现聊天功能的实例代码
Apr 19 #Javascript
You might like
Function eregi is deprecated (解决方法)
2013/06/21 PHP
php中autoload的用法总结
2013/11/08 PHP
PHP异常Parse error: syntax error, unexpected T_VAR错误解决方法
2014/05/06 PHP
常用的php图片处理类(水印、等比缩放、固定高宽)分享
2015/06/19 PHP
Javascript对象中关于setTimeout和setInterval的this介绍
2012/07/21 Javascript
关于js注册事件的常用方法
2013/04/03 Javascript
js操纵跨frame的三级联动select下拉选项实例介绍
2013/05/19 Javascript
了解了这些才能开始发挥jQuery的威力
2013/10/10 Javascript
jQuery Validate表单验证深入学习
2015/12/18 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
JS产生随机数的用法小结
2016/12/10 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
Vue组件tree实现树形菜单
2017/04/13 Javascript
AngularJS创建一个上传照片的指令实例代码
2018/02/24 Javascript
vue通过滚动行为实现从列表到详情,返回列表原位置的方法
2018/08/31 Javascript
微信小程序传值以及获取值方法的详解
2019/04/29 Javascript
vue 父组件通过$refs获取子组件的值和方法详解
2019/11/07 Javascript
vue 输入电话号码自动按3-4-4分割功能的实现代码
2020/04/30 Javascript
浏览器JavaScript调试功能无法使用解决方案
2020/09/18 Javascript
[02:15]2014DOTA2国际邀请赛 专访LGD.lin小兔子是大腿
2014/07/14 DOTA
使用python删除nginx缓存文件示例(python文件操作)
2014/03/26 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
Tkinter中复选菜单是否被选中的判断与设置方式
2020/03/04 Python
jupyter notebook 恢复误删单元格或者历史代码的实现
2020/04/17 Python
python中封包建立过程实例
2021/02/18 Python
python快速安装OpenCV的步骤记录
2021/02/22 Python
"引用"与指针的区别是什么
2016/09/07 面试题
实习自我鉴定范文
2013/10/30 职场文书
广告传媒专业应届生求职信
2014/03/01 职场文书
村干部培训班主持词
2014/03/28 职场文书
小学生综合素质评语
2014/04/23 职场文书
2015年小学教师培训工作总结
2015/07/21 职场文书
关爱空巢老人感想
2015/08/11 职场文书
庆祝教师节主题班会
2015/08/17 职场文书
go使用Gin框架利用阿里云实现短信验证码功能
2021/08/04 Golang
Java org.w3c.dom.Document 类方法引用报错
2021/08/07 Java/Android