有许多理由让你在页面中加入拖放的功能,其中最简单的理由是重新组织数据。举个例子,你可能希望用户能够重组一系列的页面元素,通过放置一个input或 select组件在各个元素的旁边来代表它们的顺序是一种解决方案,使该组元素可以被拖放是一种替代方案。或者也许你想在网站上拥有一个可以被用户移动的 导航窗口。这些都是使用拖放功能的简单理由,因为你能够实现!
在你的网页上实现拖放的效果并不是很复杂。首先,我们知道鼠标的位置,然后我们需要了解用户什么时候点击一个元素,以至于我们知道要准备开始拖动它,最后我们要移动这个元素。
捕获鼠标的移动
第一步,我们需要获取鼠标的坐标,通过一个函数并赋给document.onmousemove可以实现这一功能:
- document.onmousemove = mouseMove;
- function mouseMove(ev) {
- ev = ev || window.event;
- var mousePos = mouseCoords(ev);
- }
- function mouseCoords(ev) {
- if(ev.pageX || ev.pageY) {
- return {x:ev.pageX, y:ev.pageY};
- }
- return {
- x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
- y:ev.clientY + document.body.scrollTop - document.body.clientTop
- };
- }
首先我们需要解释一下event对象。不论你什么时候移动、点击鼠标,或按键,等等,一个事件都会发生。在IE中,这个事件是全局的,它被存储在 window.event中,对于Firefox,及其他的浏览器来说,这个事件将被传递到任何指向这个页面动作的函数中。因此,我们使 document.onmousemove指向鼠标移动的函数,鼠标移动的函数获得事件对象。
上述代码中,ev在所有浏览器环境中都包含了event对象。在Firefox里,"||window.event"将被忽略,因为它已经包含事件。在IE中,ev的值为空,以至于需要将它的值设置为window.event。
本文中我们需要多次捕获到鼠标的坐标,因此我们写了一个mouseCoords方法,它有一个参数:event。
我们要再次讨论IE和其他浏览器之间的差异。Firefox和其他的浏览器使用event.pageX和event.pageY来表示鼠标相对于 document文档的位置。如果你有一个500*500的窗口,并且鼠标位于窗口中间,那么pageX和pageY的值将都是250。如果你将窗口向下 滚动500象素,pageY的值为750。
如此相反的是,微软的IE使用event.clientX和event.clientY来表示鼠标相对于window窗口的位置,而不是当前 document文档。在相同的例子中,如果将鼠标放置于500*500窗口的中间,clientX和clientY值将均为250。如果向下滚动页面, clientY将仍为250,因为它是相对于window窗口来测量,而不是当前的document文档。因此,在鼠标位置中,我们应该引入 document文档body区域的scrollLeft和scrollTop属性。最后,IE中document文档实际并不在(0,0)的位置,在它 周围有一个小(通常有2px)边框,document.body.clientLeft和document.body.clientTop包含了这个边框 的宽度,从而还需要在鼠标位置中引入它们。
幸运的是,现在我们拥有了mouseCoords函数,不用再为获取鼠标位置担心了。
捕获鼠标的点击
下一步,我们必须知道鼠标何时点击及何时释放。如果我们跳过这一步,只要你的鼠标移动经过这些元素时,都将产生拖动这些元素的效果,这是令人讨厌并违反人的直觉的。
在这里,有两个函数可以帮助我们:onmousedown和onmouseup。先前我们已将document.onmousemove指向一个函数,因 此从逻辑上似乎应该使document.onmousedown和document.onmouseup都指向函数。如果我们让 document.onmousedown指向一个函数,那么这个函数将会因为鼠标点击任何元素而执行:文本、图像、表格,等等。我们只想页面中特定的元 素具有被拖放的功能,因此,我们可以通过如下方法实现:
- document.onmouseup = mouseUp;
- var dragObject = null;
- function makeClickable(object) {
- object.onmousedown = function() {
- dragObject = this;
- }
- }
- function mouseUp(ev) {
- dragObject = null;
- }
我们现在有了一个变量dragObject,包含了你点击的任何元素。当你释放鼠标的时候,dragObject被设置为空,从而在dragObject非空的时候,我们需要进行拖动操作。
移动元素
我们现在已经知道如何捕获鼠标移动和点击。接下来需要做的就是移动任何我们想拖动的元素。首先,将一个元素准确移动到页面上我们想要的位置,该元素样式表 的position值必须为absolute,这意味着你可以设置它的style.top或style.left,测量值相对于页面的左上角,因为我们所 有的鼠标移动都是相对于页面左上角的,通常都是这样。
一旦我们设置了item.style.position='absolute',接下来就需要改变该元素top和left的位置,使它移动!
- document.onmousemove = mouseMove;
- document.onmouseup = mouseUp;
- var dragObject = null ;
- var mouseOffset = null ;
- function getMouseOffset(target, ev) {
- ev = ev || window.event;
- var docPos = getPosition(target);
- var mousePos = mouseCoords(ev);
- return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y} ;
- }
- function getPosition(e) {
- var left = 0;
- var top = 0;
- while (e.offsetParent) {
- left += e.offsetLeft;
- top += e.offsetTop;
- e = e.offsetParent;
- }
- left += e.offsetLeft;
- top += e.offsetTop;
- return {x:left, y:top} ;
- }
- function mouseMove(ev) {
- ev = ev || window.event;
- var mousePos = mouseCoords(ev);
- if (dragObject) {
- dragObject.style.position = 'absolute';
- dragObject.style.top = mousePos.y - mouseOffset.y;
- dragObject.style.left = mousePos.x - mouseOffset.x;
- return false ;
- }
- }
- function mouseUp() {
- dragObject = null ;
- }
- function makeDraggable(item) {
- if (!item) return ;
- item.onmousedown = function (ev) {
- dragObject = this ;
- mouseOffset = getMouseOffset(this, ev);
- return false ;
- }
- }
你会注意到这些代码是以我们前面的例子为基础的(参考上篇文章),将它们放置在一起,你将能够随意的去移动元素。
当我们点击一个元素时,存储了另外的一个变量,mouseOffset。mouseOffset简单的包含了我们点击元素的位置信息。如果我们有一张 20*20px的图像,然后点击图像的中间,mouseOffset应该是{x:10, y:10}。如果我们点击图像的左上角,mouseOffset应为{x:0, y:0}。我们在鼠标移动后的位置信息中用到它。如果我们没有存储这个值,不论你点击元素的哪一个位置,元素相对于鼠标的位置都将会是相同的。
mouseOffset函数用到了另外一个函数getPosition。getPosition目的是返回元素相对于documemt文档的坐标位置。如 果我们简单的去读取item.offsetLeft或item.style.left,得到的将是元素相对于它父元素的位置,而不是document文档 的。在我们的脚本中,所有的元素都是相对于document文档的,因此需要这样做。
要完成获取元素相对于document文档位置的工作,getPosition从它自身的父级开始,循环获取它的left和top的值并累加,这样我们就得到了我们想要的元素距文档顶部和左侧的累计值。
当我们获取了这条信息并移动鼠标的时候,mouseMove开始运行。首先我们需要保证item.style.position值为absolute,接 着,我们将元素移动到任何一个地方,鼠标位置都会减去我们之前记录的鼠标相对于元素的偏移量。当鼠标释放时,dragObject将被设置为null,并 且mouseMove函数不再做任何事情。
放置元素
我们前面的例子已经处理了这个问题,仅仅是拖动一个元素,然后将它放下。然后,在我们放下元素的时候通常还有其他的目的,我们以拖动元素到垃圾回收站为例,或我们可能想让该元素和页面中某个特定的区域对齐。
不幸的是我们在这里进入了一个相对主要的问题。因为我们正在移动的元素总是直接处于我们的鼠标下,而不可能去引发mouseover、 mousedown、mouseup或鼠标对页面中其他元素的操作。如果你移动一个元素到垃圾回收站,你的鼠标会一直在移动元素的上方,而不是垃圾回收 站。
那么我们该如何处理这个问题呢?这里有几种解决方案。在前面所提到的mouseOffset的目的是保证元素总是在鼠标下方正确的位置,如果你忽视了这 点,然后总是使得元素在鼠标的右下方,你的鼠标将不会被你正在拖动的元素所隐藏,我们也不会碰到问题。但事实上往往不会这样,为了美观我们通常要保持元素 在鼠标的下方。
另外一种选择是不移动你正在拖动的元素,你可以改变鼠标样式,来告诉使用者你正在拖动一个元素,直到你将它放置到某个地方。这解决了我们的问题,但是带来了和前面一种方案面临的同样问题:美观。
我们最后的一种解决方案既不影响你正在移动的元素,也不影响移动终点位置上的元素(例如垃圾回收站)。不幸的是,这比前面两种解决方案的难度更大。我们将 要做的是获得一组我们要放置的目标,当鼠标释放时,我们手工检查当前鼠标相对于每个目标的位置,看鼠标是否释放在这个目标中某一个目标的位置上,如果是 的,我们就知道我们已经将元素放置在我们的目标上了。
- /**/ /*
- All code from the previous example is needed with the exception
- of the mouseUp function which is replaced below
- */
- var dropTargets = [];
- function addDropTarget(dropTarget) {
- dropTargets.push(dropTarget);
- }
- function mouseUp(ev) {
- ev = ev || window.event;
- var mousePos = mouseCoords(ev);
- for (var i = 0; i < dropTargets.length; i ++) {
- var curTarget = dropTargets[i];
- var targPos = getPosition(curTarget);
- var targWidth = parseInt(curTarget.offsetWidth);
- var targHeight = parseInt(curTarget.offsetHeight);
- if (
- (mousePos.x > targPos.x) &&
- (mousePos. < (targPos.x + targWidth)) &&
- (mousePos.y > targPos.y) &&
- (mousePos.y < (targPos.y + targHeight))) {
- // dragObject was dropped onto curTarget!
- }
- }
- dragObject = null ;
- }
这个例子中当鼠标释放时,我们循环每个可能放置元素的目标,如果鼠标指针在目标上,我们则拥有了一个放置元素的事件,通过鼠标横坐标大于目标元素左侧横坐 标(mousePos.x>targPos.x),小于目标元素右侧横坐标(mousePos.x<(targPos.x+ targWidth))来判定,对于Y坐标我们做同样的判断。如果所有的这些值都返回true,那么我们的鼠标就是在目标元素的范围内。
整合所有的功能
最后我们使用所有代码片断,来创建一个完整的拖放函数脚本。我们所要做的第一件事情是DOM操作,如果你对此并不十分熟悉,可以阅读《JavaScript Primer on DOM Manipulation》。
接下来的代码创建容器和容器组,使得在这些容器中可以拖动每个元素,这在本文第二个demo的基础上来完成。这段代码能够用来重新规划元素的顺序,将导航窗口放在页面的左侧或右侧,或再加入你所能想到的其他的功能。
我们将使用伪代码来一步步进行讲解,将真实的代码通过注释的方式留给读者查看。
1.当文档第一次被加载时,我们创建一个名为dragHelper的DIV标签,当我们开始移动一个元素的时候,dragHelper将成为一个隐藏元 素,可以四处移动。真实的元素并不会被拖动,仅仅使用insertBefore和appendChild来移动。我们在开始的时候隐藏 dragHelper。
2.我们创建mouseDown和mouseUp函数。起初,所有的这些函数都假设记录了鼠标按钮的状态,以至于iMouseDown变量在鼠标按下的时候为true,没有按下的时候为false。
3.我们创建一个全局变量DragDrops,以及一个函数CreateDragContainer。DragDrops包含一组相互关联的容器。传入 CreateDragContainer的任何变量(代表容器)被组织成一个新的集合,使元素能够在这些容器间自由移动。通过setAttribute, CreateDragContainer函数同样将各容器中的元素绑定在一起。
4.现在我们的代码知道每个元素所在的集合,现在来看mouseMove函数。mouseMove函数首先设置了一个变量target,表示鼠标下面的目标元素,如果这个元素在集合(用getAttribute判断)中就继续下面操作:
4.1.首先,在必要的时候,我们运行一个简单的脚本来改变目标元素的class属性,这样就创造了一个翻动的效果。
4.2.然后我们检查鼠标是否点击(因为我们的代码已经运行到这里),如果事件发生:
4.2.1.设置变量curTarget为当前元素。
4.2.2.记录元素当前在文档中的位置,以便在需要的时候可以将它的值取回。
4.2.3.将当前元素克隆到dragHelper,使得我们能够移动元素的隐藏备份。
4.2.4.因为在dragHelper中我们完全拥有了拖动元素的一个备份,这个元素会始终在鼠标下,我们必须移除dragObj属性,让代码知道dragObj已不在集合中。
4.2.5.我们快速记录集合中每个元素当前的位置、宽度和高度。当元素第一次开始被拖动时,我们仅需做一次这种工作,否则每当鼠标移动的时候我们都必须做一次,甚至一秒内几百次。
4.3.如果鼠标没有点击,要么我们和之前拥有同样的目标元素,要么没有目标元素,不论哪种情况我们都不会做任何事情。
5.现在我们检查curTarget变量。curTarget应该仅包含一个被拖动的对象,因此如果它存在,表示我们正在拖动一个元素:
5.1.移动隐藏DIV到鼠标,这个元素和文章前面所创建的元素一样能够被拖动。
5.2.然后我们检查鼠标是否存在于当前集合中每个容器中。
5.2.1.如果鼠标在某个容器中,我们检查容器中的每个元素,查看我们正拖动的元素属于哪个位置。
5.2.2.然后我们将所拖动的元素放置在容器中另一个元素的前面,或容器的最后位置。
5.2.3.最后我们确定元素可见。
6.剩下的事情就是捕获mouseUp事件:
6.1.首先需要隐藏dragHelper:它不再被需要,因为我们没有拖动任何东西。
6.2.如果拖动的元素是可见的,它已经存在于任何它所属的容器中,所有工作已完成。
6.3.如果拖动的元素不可见,我们将它放回它原来所在的地方。
- // iMouseDown represents the current mouse button state: up or down
- /**//*
- lMouseState represents the previous mouse button state so that we can
- check for button clicks and button releases:
- if(iMouseDown && !lMouseState) // button just clicked!
- if(!iMouseDown && lMouseState) // button just released!
- */
- var mouseOffset = null;
- var iMouseDown = false;
- var lMouseState = false;
- var dragObject = null;
- // Demo 0 variables
- var DragDrops = [];
- var curTarget = null;
- var lastTarget = null;
- var dragHelper = null;
- var tempDiv = null;
- var rootParent = null;
- var rootSibling = null;
- Number.prototype.NaN0=function(){return isNaN(this)?0:this;}
- function CreateDragContainer(){
- /**//*
- Create a new "Container Instance" so that items from one "Set" can not
- be dragged into items from another "Set"
- */
- var cDrag = DragDrops.length;
- DragDrops[cDrag] = [];
- /**//*
- Each item passed to this function should be a "container". Store each
- of these items in our current container
- */
- for(var i=0; i<arguments.length; i++){
- var cObj = arguments[i];
- DragDrops[cDrag].push(cObj);
- cObj.setAttribute('DropObj', cDrag);
- /**//*
- Every top level item in these containers should be draggable. Do this
- by setting the DragObj attribute on each item and then later checking
- this attribute in the mouseMove function
- */
- for(var j=0; j<cObj.childNodes.length; j++){
- // Firefox puts in lots of #text nodesskip these
- if(cObj.childNodes[j].nodeName=='#text') continue;
- cObj.childNodes[j].setAttribute('DragObj', cDrag);
- }
- }
- }
- function mouseMove(ev){
- ev = ev || window.event;
- /**//*
- We are setting target to whatever item the mouse is currently on
- Firefox uses event.target here, MSIE uses event.srcElement
- */
- var target = ev.target || ev.srcElement;
- var mousePos = mouseCoords(ev);
- // mouseOut event - fires if the item the mouse is on has changed
- if(lastTarget && (target!==lastTarget)){
- // reset the classname for the target element
- var origClass = lastTarget.getAttribute('origClass');
- if(origClass) lastTarget.className = origClass;
- }
- /**//*
- dragObj is the grouping our item is in (set from the createDragContainer function).
- if the item is not in a grouping we ignore it since it can't be dragged with this
- script.
- */
- var dragObj = target.getAttribute('DragObj');
- // if the mouse was moved over an element that is draggable
- if(dragObj!=null){
- // mouseOver event - Change the item's class if necessary
- if(target!=lastTarget){
- var oClass = target.getAttribute('overClass');
- if(oClass){
- target.setAttribute('origClass', target.className);
- target.className = oClass;
- }
- }
- // if the user is just starting to drag the element
- if(iMouseDown && !lMouseState){
- // mouseDown target
- curTarget = target;
- // Record the mouse x and y offset for the element
- rootParent = curTarget.parentNode;
- rootSibling = curTarget.nextSibling;
- mouseOffset = getMouseOffset(target, ev);
- // We remove anything that is in our dragHelper DIV so we can put a new item in it.
- for(var i=0; i<dragHelper.childNodes.length; i++) dragHelper.removeChild(dragHelper.childNodes[i]);
- // Make a copy of the current item and put it in our drag helper.
- dragHelper.appendChild(curTarget.cloneNode(true));
- dragHelper.style.display = 'block';
- // set the class on our helper DIV if necessary
- var dragClass = curTarget.getAttribute('dragClass');
- if(dragClass){
- dragHelper.firstChild.className = dragClass;
- }
- // disable dragging from our helper DIV (it's already being dragged)
- dragHelper.firstChild.removeAttribute('DragObj');
- /**//*
- Record the current position of all drag/drop targets related
- to the element. We do this here so that we do not have to do
- it on the general mouse move event which fires when the mouse
- moves even 1 pixel. If we don't do this here the script
- would run much slower.
- */
- var dragConts = DragDrops[dragObj];
- /**//*
- first record the width/height of our drag item. Then hide it since
- it is going to (potentially) be moved out of its parent.
- */
- curTarget.setAttribute('startWidth', parseInt(curTarget.offsetWidth));
- curTarget.setAttribute('startHeight', parseInt(curTarget.offsetHeight));
- curTarget.style.display = 'none';
- // loop through each possible drop container
- for(var i=0; i<dragConts.length; i++){
- with(dragConts[i]){
- var pos = getPosition(dragConts[i]);
- /**//*
- save the width, height and position of each container.
- Even though we are saving the width and height of each
- container back to the container this is much faster because
- we are saving the number and do not have to run through
- any calculations again. Also, offsetHeight and offsetWidth
- are both fairly slow. You would never normally notice any
- performance hit from these two functions but our code is
- going to be running hundreds of times each second so every
- little bit helps!
- Note that the biggest performance gain here, by far, comes
- from not having to run through the getPosition function
- hundreds of times.
- */
- setAttribute('startWidth', parseInt(offsetWidth));
- setAttribute('startHeight', parseInt(offsetHeight));
- setAttribute('startLeft', pos.x);
- setAttribute('startTop', pos.y);
- }
- // loop through each child element of each container
- for(var j=0; j<dragConts[i].childNodes.length; j++){
- with(dragConts[i].childNodes[j]){
- if((nodeName=='#text') || (dragConts[i].childNodes[j]==curTarget)) continue;
- var pos = getPosition(dragConts[i].childNodes[j]);
- // save the width, height and position of each element
- setAttribute('startWidth', parseInt(offsetWidth));
- setAttribute('startHeight', parseInt(offsetHeight));
- setAttribute('startLeft', pos.x);
- setAttribute('startTop', pos.y);
- }
- }
- }
- }
- }
- // If we get in here we are dragging something
- if(curTarget){
- // move our helper div to wherever the mouse is (adjusted by mouseOffset)
- dragHelper.style.top = mousePos.y - mouseOffset.y;
- dragHelper.style.left = mousePos.x - mouseOffset.x;
- var dragConts = DragDrops[curTarget.getAttribute('DragObj')];
- var activeCont = null;
- var xPos = mousePos.x - mouseOffset.x + (parseInt(curTarget.getAttribute('startWidth')) /2);
- var yPos = mousePos.y - mouseOffset.y + (parseInt(curTarget.getAttribute('startHeight'))/2);
- // check each drop container to see if our target object is "inside" the container
- for(var i=0; i<dragConts.length; i++){
- with(dragConts[i]){
- if(((getAttribute('startLeft')) < xPos) &&
- ((getAttribute('startTop')) < yPos) &&
- ((getAttribute('startLeft') + getAttribute('startWidth')) > xPos) &&
- ((getAttribute('startTop') + getAttribute('startHeight')) > yPos)){
- /**//*
- our target is inside of our container so save the container into
- the activeCont variable and then exit the loop since we no longer
- need to check the rest of the containers
- */
- activeCont = dragConts[i];
- // exit the for loop
- break;
- }
- }
- }
- // Our target object is in one of our containers. Check to see where our div belongs
- if(activeCont){
- // beforeNode will hold the first node AFTER where our div belongs
- var beforeNode = null;
- // loop through each child node (skipping text nodes).
- for(var i=activeCont.childNodes.length-1; i>=0; i--){
- with(activeCont.childNodes[i]){
- if(nodeName=='#text') continue;
- // if the current item is "After" the item being dragged
- if(
- curTarget != activeCont.childNodes[i] &&
- ((getAttribute('startLeft') + getAttribute('startWidth')) > xPos) &&
- ((getAttribute('startTop') + getAttribute('startHeight')) > yPos)){
- beforeNode = activeCont.childNodes[i];
- }
- }
- }
- // the item being dragged belongs before another item
- if(beforeNode){
- if(beforeNode!=curTarget.nextSibling){
- activeCont.insertBefore(curTarget, beforeNode);
- }
- // the item being dragged belongs at the end of the current container
- } else {
- if((curTarget.nextSibling) || (curTarget.parentNode!=activeCont)){
- activeCont.appendChild(curTarget);
- }
- }
- // make our drag item visible
- if(curTarget.style.display!=''){
- curTarget.style.display = '';
- }
- } else {
- // our drag item is not in a container, so hide it.
- if(curTarget.style.display!='none'){
- curTarget.style.display = 'none';
- }
- }
- }
- // track the current mouse state so we can compare against it next time
- lMouseState = iMouseDown;
- // mouseMove target
- lastTarget = target;
- // track the current mouse state so we can compare against it next time
- lMouseState = iMouseDown;
- // this helps prevent items on the page from being highlighted while dragging
- return false;
- }
- function mouseUp(ev){
- if(curTarget){
- // hide our helper object - it is no longer needed
- dragHelper.style.display = 'none';
- // if the drag item is invisible put it back where it was before moving it
- if(curTarget.style.display == 'none'){
- if(rootSibling){
- rootParent.insertBefore(curTarget, rootSibling);
- } else {
- rootParent.appendChild(curTarget);
- }
- }
- // make sure the drag item is visible
- curTarget.style.display = '';
- }
- curTarget = null;
- iMouseDown = false;
- }
- function mouseDown(){
- iMouseDown = true;
- if(lastTarget){
- return false;
- }
- }
- document.onmousemove = mouseMove;
- document.onmousedown = mouseDown;
- document.onmouseup = mouseUp;
- window.onload = function(){
- // Create our helper object that will show the item while dragging
- dragHelper = document.createElement('DIV');
- dragHelper.style.cssText = 'position:absolute;display:none;';
- CreateDragContainer(
- document.getElementById('DragContainer1'),
- document.getElementById('DragContainer2'),
- document.getElementById('DragContainer3')
- );
- document.body.appendChild(dragHelper);
- }
- <!-- the mouse over and dragging class are defined on each item -->
- <div class ="DragContainer" id="DragContainer1">
- <div class="DragBox" id="Item1" overClass="OverDragBox" dragClass="DragDragBox">Item #1</div>
- <div class="DragBox" id="Item2" overClass="OverDragBox" dragClass="DragDragBox">Item #2</div>
- <div class="DragBox" id="Item3" overClass="OverDragBox" dragClass="DragDragBox">Item #3</div>
- <div class="DragBox" id="Item4" overClass="OverDragBox" dragClass="DragDragBox">Item #4</div>
- </div>
- <div class="DragContainer" id="DragContainer2" >
- <div class="DragBox" id="Item5" overClass="OverDragBox" dragClass="DragDragBox">Item #5</div>
- <div class="DragBox" id="Item6" overClass="OverDragBox" dragClass="DragDragBox">Item #6</div>
- <div class="DragBox" id="Item7" overClass="OverDragBox" dragClass="DragDragBox">Item #7</div>
- <div class="DragBox" id="Item8" overClass="OverDragBox" dragClass="DragDragBox">Item #8</div>
- </div>
- <div class="DragContainer" id="DragContainer3">
- <div class="DragBox" id="Item9" overClass="OverDragBox" dragClass="DragDragBox">Item #9</div>
- <div class="DragBox" id="Item10" overClass="OverDragBox" dragClass="DragDragBox">Item #10</div>
- <div class="DragBox" id="Item11" overClass="OverDragBox" dragClass="DragDragBox">Item #11</div>
- <div class="DragBox" id="Item12" overClass="OverDragBox" dragClass="DragDragBox">Item #12</div>
- </div>
关于作者
Mark Kahn是一位Web Developer、DBA。可以通过这个网址跟他联系:http://www.jslibrary.org
原文链接:http://www.webreference.com/programming/javascript/mk/column2/3.html
译文链接:http://www.blogjava.net/flyingis/archive/2006/10/15/75277.html