简易而又灵活的Javascript拖拽框架(四)
一、开篇
似乎拖拽已经被写烂了,没得写的了,可是我这次又来了~
上一次写的是跨列拖放,这次我要带给大家的是跨页拖放。
可以到这里来看看效果:示例效果
说明:1、如果将方框拖动到页签上立刻释放掉的话,则会被添加到该页的第一列的第一个位置;
2、如果将方框拖动到页签上并且停留片刻的话,则页面就会转换到该页,这个时候可以在页签上释放,也可以将方框拖动到此页的具体位置释放。
二、原理
我是在跨列拖放的基础上修改的代码,虽然仅仅是从跨“列”升级为跨“页“,但是这就意味着多了一个dimension。所以代码改动比较大,尤其是初始化的代码。
为了弄清楚代码中的命名同时也便于阐述原理,我画了下面的图
1、在拖动开始时,跟之前的跨列拖拽差不多,基本上不需要修改;
2、在拖动的过程中,就需要判断拖动module时的鼠标是否是在某个tab上,如果在tab上,则把dragGhost(拖动中占位的虚线框)隐藏了,并且设置转换页面的timeout(注意:这个timeout不要设置重复了,而且如果鼠标就在本页上就不需要设置),在设置这个timeout的响应函数也要小心,必须先把拖动的module放到新的页面然后再转换页面,因为鼠标虽然拖动了module,但是在html代码中,这个module还是属于原来的页面(只是因为position为absolute才让它游离出来的),如果原来的页面因为页面转换而变得不可见了,那么鼠标拖动的module也会不翼而飞的。
3、在拖动的过程中,如果鼠标不在某个tab上,首先要将timeout及时清除了,要不然在拖动时会莫名其妙的转换页面,剩下的跟页面内拖放是一样的计算方法来处理,也是先计算所在的列,然后计算再这个列的位置,在此不再累述。
4、在拖动的过程中,注意维持module的column变量,这个变量对于拖放很重要,要及时而正确的更新。
5、在拖动结束的时候,如果鼠标还在某个tab上(无论这个时候页面是不是因为鼠标的停留而改变),则把module放在这一页的第一列的第一个位置。如果不在tab上,那么和页面内拖放是一样的。无论怎样,在最后都要设置一些style以及更新个别变量,放置完毕。
三、代码
原理说起来容易,写起来还是很麻烦的,而且得经过很多次测试才能成功的。
不过我总结出来几点:
1、对于任何一个对象,要分清楚这个对象是html对象还是我们自定义类的对象;
2、各种对象尽量少维持一些变量,要不然在每次动作发生的时候都会去更新一堆变量,那将是很麻烦的(或许可以将这些变量的设置封装成对象的方法);
主要代码如下:
var module = function(moduleElm){
var self = this;
this.elm = moduleElm;
this.elm.module = this;
this.column = moduleElm.column;
this.page = this.column.page;
this.handle = this.elm.getElementsByTagName("h3")[0];
//这里只是为了各个页面的module看起来不一样 所以另外设置一下style
//page的id也是为了这个目的而加的 其他地方page的id是用不上的
switch(this.page.id){
case "page1":this.handle.style.backgroundColor="red";break;
case "page2":this.handle.style.backgroundColor="blue";break;
case "page3":this.handle.style.backgroundColor="black";break;
case "page4":this.handle.style.backgroundColor="#CCCCCC";break;
}
if(this.handle && this.elm){
Drag.init(this.handle,this.elm);
}else{
return;
}
this.elm.onDragStart = function(left,top,mouseX,mouseY){
//开始拖动的时候设置透明度
this.style.opacity = "0.5";
this.style.filter = "alpha(opacity=50)";
dragGhost.style.height = isIE?this.offsetHeight:this.offsetHeight - 2;
//this指的是item
this.style.width = this.offsetWidth;//因为初始的width为auto
this.style.left = findPosX(this) - 5;
this.style.top = findPosY(this) - 5;
this.style.position = "absolute";
//将ghost插入到当前位置
dragGhost.style.display = "block";
self.column.insertBefore(dragGhost,this);
//记录每一列的左边距 在拖动过程中判断拖动对象所在的列会用到
this.columnsX = [];
for(var i=0;i<self.column.page.columns.length;i++){
this.columnsX.push(findPosX(self.column.page.columns[i]));
}
}
this.elm.onDrag = function(left,top,mouseX,mouseY){
this.currentTab = null;
//判断是否在tab上
for(var i=0;i<XDrag.tabs.length;i++){
var tabElm = XDrag.tabs[i].elm;
if((findPosX(tabElm) < mouseX) &&
(findPosX(tabElm) + tabElm.offsetWidth > mouseX) &&
(findPosY(tabElm) < mouseY) &&
(findPosY(tabElm) + tabElm.offsetHeight > mouseY)){
this.currentTab = XDrag.tabs[i];
break;
}
}
if(this.currentTab != null){
if(dragGhost.parentNode)
dragGhost.parentNode.removeChild(dragGhost);
function changeTab(){
//先得把module放到当前的这一页
//否则会随着tab的改变而消失
var currentColumn = self.elm.currentTab.page.columns[0];
var flag = false;
for(var i=0;i<currentColumn.childNodes.length;i++){
if(currentColumn.childNodes[i].nodeName.toLowerCase() == "div"){
currentColumn.insertBefore(self.elm,currentColumn.childNodes[i]);
flag = true;
break;
}
}
if(!flag)
currentColumn.appendChild(this);
self.column = currentColumn;//将拖动的module添加到这一页的第一列 因为display还为absolute 所以module还跟着鼠标在走
self.elm.currentTab.select();
XDrag.changeTabTimeoutId == null;
}
//如果Timeout不为空(防止重复设置Timeout) 而且移动到的tab不是当前的tab(如果是当前tab则不需要改变tab页了)
if(XDrag.changeTabTimeoutId == null && this.currentTab != XDrag.selectedTab)
XDrag.changeTabTimeoutId = setTimeout(changeTab,XDrag.changeTabTimeout);
return;//如果鼠标在tab上 则不必理会页面内的移动了
}
//以下是计算在页面内拖拽的代码
clearTimeout(XDrag.changeTabTimeoutId);
XDrag.changeTabTimeoutId = null;//既然鼠标都没有在tab上了 当然就应该清空timeout了
//先要判断在哪一列移动
var columnIndex = 0;
for(var i=0;i<this.columnsX.length;i++){
if((left + this.offsetWidth/2) > this.columnsX[i]){
columnIndex = i;
}
}
//如果columnIndex在循环中没有被赋值 则表示当前拖动对象在第一列的左边
//此时也把它放到第一列
var column = self.column.page.columns[columnIndex];
if(self.column != column){
//之前拖动对象不在这个列
//将ghost放置到这一列的最下方
//如果已经跨页拖放了 也会执行这里的
column.appendChild(dragGhost);
self.column = column;
}
//然后在判断放在这一列的什么位置
var currentNode = null;
for(var i=0;i<self.column.childNodes.length;i++){
if(self.column.childNodes[i].className == "item"
&& self.column.childNodes[i] != this//不能跟拖动元素自己比较 否则不能在本列向下移动
&& top < findPosY(self.column.childNodes[i])){//从上到下找到第一个比拖动元素的上边距大的元素
currentNode = self.column.childNodes[i];
break;
}
}
if(currentNode)
self.column.insertBefore(dragGhost,currentNode);
else//拖到最下边 没有任何一个元素的上边距比拖动元素的top大 则添加到列的最后
self.column.appendChild(dragGhost);
}
this.elm.onDragEnd = function(left,top,mouseX,mouseY){
if(this.currentTab != null){
//this.currentTab != null表示鼠标拖拽的module在tab上释放 无论这个时候tab是否因为鼠标的停留而转换了页签
clearTimeout(XDrag.changeTabTimeoutId);
XDrag.changeTabTimeoutId = null;
var firstColumn = this.currentTab.page.columns[0];
var flag = false;
for(var i=0;i<firstColumn.childNodes.length;i++){
if(firstColumn.childNodes[i].nodeName.toLowerCase() == "div"){
firstColumn.insertBefore(this,firstColumn.childNodes[i]);
flag = true;
break;
}
}
if(!flag)
firstColumn.appendChild(this);
self.column = firstColumn;
}else{
self.column.insertBefore(this,dragGhost);
}
this.style.opacity = "1";
this.style.filter = "alpha(opacity=100)";
this.style.position = "static";
this.style.display = "block";
this.style.width = "auto";
dragGhost.style.display = "none";
self.page = self.column.page;//需要手动更新(奇怪 self.page难道是个值类型)
//也可以不要最后这一句 仅仅是为了数据的完整性
}
}
四、示例下载
点此下载示例
转载于:https://www.cnblogs.com/LongWay/archive/2008/09/23/1297173.html
简易而又灵活的Javascript拖拽框架(四)相关推荐
- 简易而又灵活的Javascript拖拽框架(五)
====================================================== 注:本文源代码点此下载 ================================= ...
- Javascript 拖拽的一些高级的应用——逐行分析代码,让你轻松了解拖拽的原理...
我们看看之前的拖拽在周围有东西的时候会出现什么问题? 在高级浏览器中不会有啥问题,我们放到IE7下面测试一下,问题就出来了.如图 我们可以很清楚的看到,文字都已经被选中了.那这个用户体验很不好,用起来 ...
- 功能强大的JavaScript 拖拽库 SortableJS
功能强大的JavaScript 拖拽库 SortableJS 官网:http://www.sortablejs.com/ 示例: 配置项: var sortable = new Sortable(el ...
- JavaScript 拖拽功能
JavaScript 拖拽功能 - Web前端工程师面试题讲解 拖动图片 <img draggable="true"> 一开始 html 页面 <style> ...
- JavaScript拖拽
<!DOCTYPE html><html><head> <meta charset="utf-8"> <meta http-e ...
- HTML+JavaScript拖拽进度条和点击进度条(显示进度条百分比)
实现进度条拖拽功能和点击功能,并显示占比 实现图: 附加改变区域位置,不影响进度条 完整代码 <!DOCTYPE html> <html lang="zh_CN" ...
- JavaScript拖拽函数
/此方法用于拖拽/ //参数:div1是父盒子(主要是控制要拖拽的盒子不能超出父类),div2是子盒子(即要拖动的盒子) //注意:div必须加绝对定位才能拖拽 function tuozhuai(d ...
- JavaScript拖拽事件
window.onload =function(){ /* * 拖拽box1元素* - 拖拽的流程 1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown * 2.当鼠标移动时被拖拽元素跟随 ...
- html可视化拖拽框架,前端可视化拖拽方案
技术栈:react+dva+less+umi+antd+node+ sortable umi:组件库设计考虑的一个重要的问题就是体积和渲染问题, 一旦组件库变的越来越多, 那意味着页面加载会非常慢,所 ...
最新文章
- jquery text html width heigth的用法
- ktor框架用到了netty吗_如何使用 Ktor 快速开发 Web 项目
- php可以更改html后缀名嘛,请问你们怎么将html的文件的内容改变为php
- SOA技术相关介绍(RPC, Web Service, REST,SOAP,JMI)
- 表格数据的识别与提取
- logback日志pattern_Springboot整合log4j2日志全解
- 如何为 Mac 添加新语言?
- 软路由初次尝试者的折腾指南
- 众多IT精英齐聚首尔,竟是因为这项技术……
- 怎么可以优化网站的打开速度?
- iOS手势-UIGestureRecognizer
- 【语义分割】Searching for Efficient Multi-Scale Architectures for Dense Image Prediction翻译
- Python写文件到指定路径以及读取文件内容
- 微信小程序 - 实现导航栏和内容上下联动功能
- Python “最短”挑战(12.21)
- 15个nosql数据库
- Reality Labs首次向媒体开放,空间音频、EMG腕带体验大公开
- 2022年A特种设备相关管理(电梯)考试题模拟考试平台操作
- 动力电池:车企们的新角斗场
- Linux中搜索大于200M的文件
热门文章
- acm算法模板(1)
- 10 种机器学习算法的要点(附 Python 和 R 代码)(转载)
- 百度机器人对战人类最强大脑,赢在了小数点后第二位
- H264 数据avi文件封装和拆解
- Caffe + Ubuntu 14.04 64bit + CUDA 6.5 配置说明
- MySql 踩坑小记
- LeetCode算法题-Minimum Depth of Binary Tree(Java实现)
- 分布式架构 springcloud+redis+springmvc+ springboot
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- 《算法设计》二、算法分析基础