WEB开发网
开发学院网页设计JavaScript javascript的拖放(第2部分) 阅读

javascript的拖放(第2部分)

 2009-09-14 00:00:00 来源:WEB开发网   
核心提示:实现手柄拖动的功能,就是把mousedown的事件侦听器放到handle中,javascript的拖放(第2部分),由于我们原先程序的骨架搭建得比较好,添加新功能非常容易,onDragfunction在拖动时执行,onEndfunction在拖动后鼠标弹起的那一瞬执行, 1.#2.(handle || el).onmo

实现手柄拖动的功能,就是把mousedown的事件侦听器放到handle中。由于我们原先程序的骨架搭建得比较好,添加新功能非常容易。

1.#
2.  (handle || el).onmousedown = dragstart;

   [Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]

但这不够人性化,最好是我们输入一个类名作为handle的参数,拖动类会自动根据此类名在其子孙元素寻找此元素。

01.if(handle){
02.  var cls = new RegExp("(^|\s)" + handle + "(\s|$)");
03.  for(var i=0,l=el.childNodes.length;i <l;i++){
04.    var child = el.childNodes[i];
05.    if(child.nodeType == 1 && cls.test(child.className)){
06.      _handle = child;
07.      break;
08.    }
09.  }
10.}

相应地方修改为:

1.#
2.  (_handle || el).onmousedown = dragstart;

有时如果拖动元素是个非常复杂,包含相当多东西,这样拖起来很吃内存,这时是不是拖动一个空元素是不是好一些呢?我们可以克隆原来的拖动元素,并把它加入原来元素的后面(相同z-Index,后面的会放到前面的前面)。如果要求是用手柄拖动,我们把原来的手柄也克隆过来就是。

01.if(ghosting){ // ghosting为可选参数,表示使用克隆体拖动
02.  _ghost = el.cloneNode(false);
03.  el.parentNode.insertBefore(_ghost,el.nextSibling);
04.  if(_handle){
05.    _handle = _handle.cloneNode(false);
06.    _ghost.appendChild(_handle);
07.  }
08.    !+"v1"? _ghost.style.filter = "alpha(opacity=50)" : _ghost.style.opacity = 0.5;
09.}

我们还可以增添一些回调函数(onStart,onDrag,onEnd),如果用户没有实现回调函数,我们给个空函数(function(){})它就好了。

像拖动时显示元素的坐标,我们也可以做成可选参数coords。默认为true,并在手柄上显示,但这样会覆盖住原来的一些东西,我们在拖动前把它保存到一个变量中,拖动后再还原。

另,如果是一个范围中拖动,如一个指定的容器或浏览器的可视区,当拖动元素存在margin时,其右边与下边可能会超出容器。因此我们必须取出其相应的margin,当右边与下边的坐标大于容器右边或下边的坐标时,强逼元素往左边与上边移动相应的值,那个值不用说就是margin值。我们用一个简单的getStyle()函数来取margin值,因此设置元素的margin时请以px为单位,否则在IE中会计算错误。

01.var getStyle = function(el, style){
02.  if(!+"v1"){
03.    style = style.replace(/-(w)/g, function(all, letter){
04.      return letter.toUpperCase();
05.    });
06.    var value = el.currentStyle[style];
07.    (value == "auto")&&(value = "0px" );
08.    return value;
09.  }else{
10.    return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
11.  }
12.}

最后一个较为重要的功能,当元素往右边或下边移动,让元素永远留在可视区。这怎样做到呢?我们计算元素右下角的坐标(right与bottom),然后再计算出浏览器可视区的宽与高,当right大于宽时,就让它们的差值作为浏览器的scrollLeft,bottom的情形相仿。

01.if(scroll){ //表示让滚动条与元素一起移动
02.  var doc = isQuirk ? document.body : document.documentElement;
03.  doc = options.container || doc;
04.  var a = getCoords(el).left + el.offsetWidth;
05.  var b = doc.clientWidth;
06.  if (a > b){
07.    doc.scrollLeft += a - b;
08.  }
09.  var c = getCoords(el).top + el.offsetHeight;
10.  var d = doc.clientHeight;
11.  if (c > d){
12.    doc.scrollTop += c - d;
13.  }
14.}

最后函数扩展成以下样子,功能比较多,下附文档说明:

001.//辅助函数1
002.var getCoords = function(el){
003.  var box = el.getBoundingClientRect(),
004.  doc = el.ownerDocument,
005.  body = doc.body,
006.  html = doc.documentElement,
007.  clientTop = html.clientTop || body.clientTop || 0,
008.  clientLeft = html.clientLeft || body.clientLeft || 0,
009.  top  = box.top  + (self.pageYOffset || html.scrollTop  ||  body.scrollTop ) - clientTop,
010.  left = box.left + (self.pageXOffset || html.scrollLeft ||  body.scrollLeft) - clientLeft
011.  return { 'top': top, 'left': left };
012.};
013.//辅助函数2
014.var getStyle = function(el, style){
015.  if(!+"v1"){
016.    style = style.replace(/-(w)/g, function(all, letter){
017.      return letter.toUpperCase();
018.    });
019.    var value = el.currentStyle[style];
020.    (value == "auto")&&(value = "0px" );
021.    return value;
022.  }else{
023.    return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
024.  }
025.}
026.//============================
027.var Drag = function(id){
028.  var el = document.getElementById(id),
029.  isQuirk = document.documentMode ? document.documentMode == 5 : document.compatMode && document.compatMode != "CSS1Compat",
030.  options  = arguments[1] || {},
031.  container = options.container || document.documentElement,
032.  limit = options.limit,
033.  lockX = options.lockX,
034.  lockY = options.lockY,
035.  ghosting = options.ghosting,
036.  handle = options.handle,
037.  revert = options.revert,
038.  scroll = options.scroll,
039.  coords = true || options.coords,
040.  onStart =  options.onStart || function(){},
041.  onDrag =  options.onDrag || function(){},
042.  onEnd =  options.onEnd || function(){} ,
043.  marginLeft = parseFloat(getStyle(el,"margin-left")),
044.  marginRight = parseFloat(getStyle(el,"margin-right")),
045.  marginTop =  parseFloat(getStyle(el,"margin-top")),
046.  marginBottom = parseFloat(getStyle(el,"margin-bottom")),
047.  cls,
048.  _handle,
049.  _ghost,
050.  _top,
051.  _left,
052.  _html;
053.  el.lockX = getCoords(el).left;
054.  el.lockY = getCoords(el).top;
055.  el.style.position = "absolute";
056.  if(handle){
057.    cls = new RegExp("(^|\s)" + handle + "(\s|$)");
058.    for(var i=0,l=el.childNodes.length;i<l;i++){
059.      var child = el.childNodes[i];
060.      if(child.nodeType == 1 && cls.test(child.className)){
061.        _handle = child;
062.        break;
063.      }
064.    }
065.  }
066.  _html = (_handle || el).innerHTML;
067.  var dragstart = function(e){
068.    e = e || window.event;
069.    el.offset_x = e.clientX - el.offsetLeft;
070.    el.offset_y = e.clientY - el.offsetTop;
071.    document.onmouseup = dragend;
072.    document.onmousemove = drag;
073.    if(ghosting){
074.      _ghost = el.cloneNode(false);
075.      el.parentNode.insertBefore(_ghost,el.nextSibling);
076.      if(_handle){
077.        _handle = _handle.cloneNode(false);
078.        _ghost.appendChild(_handle);
079.      }
080.        !+"v1"? _ghost.style.filter = "alpha(opacity=50)" : _ghost.style.opacity = 0.5;
081.    }
082.    (_ghost || el).style.zIndex = ++Drag.z;
083.    onStart();
084.    return false;
085.  }
086.  var drag = function(e) {
087.    e = e || window.event;
088.    el.style.cursor = "pointer";
089.      !+"v1"? document.selection.empty() : window.getSelection().removeAllRanges();
090.    _left = e.clientX - el.offset_x ;
091.    _top = e.clientY - el.offset_y;
092.    if(scroll){
093.      var doc = isQuirk ? document.body : document.documentElement;
094.      doc = options.container || doc;
095.      options.container && (options.container.style.overflow = "auto");
096.      var a = getCoords(el).left + el.offsetWidth;
097.      var b = doc.clientWidth;
098.      if (a > b){
099.        doc.scrollLeft = a - b;
100.      }
101.      var c = getCoords(el).top + el.offsetHeight;
102.      var d = doc.clientHeight;
103.      if (c > d){
104.        doc.scrollTop = c - d;
105.      }
106.    }
107.    if(limit){
108.      var _right = _left + el.offsetWidth ,
109.      _bottom = _top + el.offsetHeight,
110.      _cCoords = getCoords(container),
111.      _cLeft = _cCoords.left,
112.      _cTop = _cCoords.top,
113.      _cRight = _cLeft + container.clientWidth,
114.      _cBottom = _cTop + container.clientHeight;
115.      _left = Math.max(_left, _cLeft);
116.      _top = Math.max(_top, _cTop);
117.      if(_right > _cRight){
118.        _left = _cRight - el.offsetWidth - marginLeft - marginRight;
119.      }
120.      if(_bottom > _cBottom){
121.        _top = _cBottom - el.offsetHeight  - marginTop - marginBottom;
122.      }
123.    }
124.    lockX && ( _left = el.lockX);
125.    lockY && ( _top = el.lockY);
126.    (_ghost || el).style.left = _left + "px";
127.    (_ghost || el).style.top = _top  + "px";
128.    coords && _ghost && ((_handle || _ghost).innerHTML = _left + " x " + _top);
129.    onDrag();
130.  }
131. 
132.  var dragend = function(){
133.    document.onmouseup = null;
134.    document.onmousemove = null;
135.    _ghost && el.parentNode.removeChild(_ghost);
136.    el.style.left = _left + "px";
137.    el.style.top = _top +"px";
138.    (_handle || el).innerHTML = _html;
139.    if(revert){
140.      el.style.left = el.lockX   + "px";
141.      el.style.top = el.lockY  + "px";
142.    }
143.    onEnd();
144.  }
145.  Drag.z = 999;
146.  (_handle || el).onmousedown = dragstart;
147.}

参数类型 说明
idstring必选,拖动元素的ID
containerobject可拖的范围,必须为拖动元素的父级元素,是否为定位元素无所谓。
limitboolean默认false,与container配合使用。当值为true时,它会以container或浏览器的可视区作拖动范围。
lockXboolean默认false。当值为true时,锁定X轴,只允许上下移动。
lockYboolean默认false。当值为true时,锁定Y轴,只允许左右移动。
handlestring手柄的类名,当设置了此参数后,只允许用手柄拖动元素。
ghostingboolean默认false。当值为true时,会生成一个与拖动元素相仿的影子元素,拖动时只拖动影子元素,以减轻内存消耗。
revertboolean默认false。当值为true时,让拖动元素在拖动后回到原来的位置。
coordsboolean默认true。拖动时在手柄或影子元素上显示元素的坐标。
scrollboolean默认false。当值为true时,允许滚动条随拖动元素移动。
onStartfunction在拖动前鼠标按下的那一瞬执行。
onDragfunction在拖动时执行。
onEndfunction在拖动后鼠标弹起的那一瞬执行。

   [Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]

编缉推荐阅读以下文章

  • javascript的拖放(第1部分)

Tags:javascript 部分

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接