When the # link on the example box is active (either tab and enter or mouse click) this element can be dragged using the arrow keys. Then click enter or Esc to release. (Feel free to change these keys. I'm not sure what the release key should be set to so enter and Esc will work)
Use
1. Copy the dragDrop object behind the article.
2. Copy my addEventSimple and removeEventSimple functions, which are needed here.
3. Set keyHTML and keySpeed attributes (explanation below).
4. Make sure that the element you want to drag has a position attribute: absolute or fixed.
5. Send all draggable elements to the initElement function of the object. You can send an object or a string of object IDs. For example:
dragDrop.initElement('test');<br>dragDrop.initElement(document.getElementById('test2'));
Copy after login
6. When an element is dragged, the code will automatically add the dragged class. You can add some CSS effects.
7. If you want to do something after the user releases the element, you can add your own function to releaseElement.
Properties
You need to set two properties.
keyHTML contains the content of a link that can be accessed by the keyboard of the element that needs to be dragged. To keep the HTML simple, we only add a class with a simple style. You can structure your HTML however you want, but remember that there must be a link accessible to the keyboard. Keyboard users need focus to trigger drag events.
keySpeed is used to set the speed of keyboard dragging and how many pixels to move each time a key is pressed. I like setting it to 10, but you can try other values.
There are 7 more properties here, but they are all inside the code. They are all set to undefined during initialization, and then the corresponding functions will set them.
Drag objects
Copy the following object to your page, don’t forget to addEventSimple and removeEventSimple.
dragDrop = {
keyHTML: '
#',
keySpeed: 10, // pixels per keypress event
initialMouseX: undefined,
initialMouseY: undefined,
startX: undefined,
startY: undefined,
dXKeys: undefined,
dYKeys: undefined,
draggedObject: undefined,
initElement: function (element) {
if (typeof element == 'string')
element = document.getElementById(element);
element.onmousedown = dragDrop.startDragMouse;
element.innerHTML = dragDrop.keyHTML;
var links = element.getElementsByTagName('a');
var lastLink = links[links.length-1];
lastLink.relatedElement = element;
lastLink.onclick = dragDrop.startDragKeys;
},
startDragMouse: function (e) {
dragDrop.startDrag(this);
var evt = e || window.event;
dragDrop.initialMouseX = evt.clientX;
dragDrop.initialMouseY = evt.clientY;
addEventSimple(document,'mousemove',dragDrop.dragMouse);
addEventSimple(document,'mouseup',dragDrop.releaseElement);
return false;
},
startDragKeys: function () {
dragDrop.startDrag(this.relatedElement);
dragDrop.dXKeys = dragDrop.dYKeys = 0;
addEventSimple(document,'keydown',dragDrop.dragKeys);
addEventSimple(document,'keypress',dragDrop.switchKeyEvents);
this.blur();
return false;
},
startDrag: function (obj) {
if (dragDrop.draggedObject)
dragDrop.releaseElement();
dragDrop.startX = obj.offsetLeft;
dragDrop.startY = obj.offsetTop;
dragDrop.draggedObject = obj;
obj.className = ' dragged';
},
dragMouse: function (e) {
var evt = e || window.event;
var dX = evt.clientX - dragDrop.initialMouseX;
var dY = evt.clientY - dragDrop.initialMouseY;
dragDrop.setPosition(dX,dY);
return false;
},
dragKeys: function(e) {
var evt = e || window.event;
var key = evt.keyCode;
switch (key) {
case 37: // left
case 63234:
dragDrop.dXKeys -= dragDrop.keySpeed;
break;
case 38: // up
case 63232:
dragDrop.dYKeys -= dragDrop.keySpeed;
break;
case 39: // right
case 63235:
dragDrop.dXKeys = dragDrop.keySpeed;
break;
case 40: // down
case 63233:
dragDrop.dYKeys = dragDrop.keySpeed;
break;
case 13: // enter
case 27: // escape
dragDrop.releaseElement();
return false;
default:
return true;
}
dragDrop.setPosition(dragDrop.dXKeys,dragDrop.dYKeys);
if (evt.preventDefault)
evt.preventDefault();
return false;
},
setPosition: function (dx,dy) {
dragDrop.draggedObject.style.left = dragDrop.startX dx 'px';
dragDrop.draggedObject.style.top = dragDrop.startY dy 'px';
},
switchKeyEvents: function () {
// for Opera and Safari 1.3
removeEventSimple(document,'keydown',dragDrop.dragKeys);
removeEventSimple(document,'keypress',dragDrop.switchKeyEvents);
addEventSimple(document,'keypress',dragDrop.dragKeys);
},
releaseElement: function() {
removeEventSimple(document,'mousemove',dragDrop.dragMouse);
removeEventSimple(document,'mouseup',dragDrop.releaseElement);
removeEventSimple(document,'keypress',dragDrop.dragKeys);
removeEventSimple(document,'keypress',dragDrop.switchKeyEvents);
removeEventSimple(document,'keydown',dragDrop.dragKeys);
dragDrop.draggedObject.className = dragDrop.draggedObject.className.replace(/dragged/,'');
dragDrop.draggedObject = null;
}
}
What is drag
Drag is a method of moving elements on the screen. In order for an element to move, the element must have a position attribute: absolute or fixed, so that it can be moved by modifying its coordinates (style.top and style.left).
(Theoretically position:relative is also possible, but it is almost useless. In addition, it requires additional data to calculate, which I did not write here)
Setting coordinates is very simple; finding the coordinates of the element that needs to be set is this code The harder part. Most of the code is designed to handle this problem.
In addition, maintaining ease of use is also important. Traditionally, dragging an element with the mouse is the best way, but users who do not have a mouse must also be considered, so the availability of the keyboard must also be ensured.
Basics
Let’s look at some basics first
Initializing an element
Every drag and drop code starts by initializing the element. This work is completed through the following letter:
initElement: function ( element) {
if (typeof element == 'string')
element = document.getElementById(element);
element.onmousedown = dragDrop.startDragMouse;
element.innerHTML = dragDrop.keyHTML;
var links = element.getElementsByTagName('a');
var lastLink = links[links.length-1];
lastLink.relatedElement = element;
lastLink.onclick = dragDrop.startDragKeys;
},
If the function receives a string, it will be processed as an element ID. Then set an onmousedown event for this element to start the mouse part of the code. Note that I am using the traditional event registration method here; because I want this keyword to work in startDragDrop.
Then add the user defined keyHTML to the element, I believe this link is used to trigger the keyboard event. Then set the keyboard trigger program for this link. Then store the main element in relatedElement, which we will need later.
Now the code is waiting for user action
Basic position information
I plan to use the following method: First, I will read the initial position of the dragged element and save it in startX and startY in. Then calculate the position of the mouse movement or the position of the movement under keyboard control to determine the range of movement of the element from the initial position.
startX and startY are set through the startDrag function, which is used in mouse and keyboard events.
startDrag: function (obj) {
if ( dragDrop.draggedObject)
dragDrop.releaseElement();
dragDrop.startX = obj.offsetLeft;
dragDrop.startY = obj.offsetTop;
dragDrop.draggedObject = obj;
obj.className = 'dragged';
},
First, if the element is in a dragged state, then we release it (we will talk about it later).
Then the function will find the coordinates of the element at the starting position (offsetLeft and offsetTop), and then save them in startX and startY for later use.
Then save a reference to the object in draggedObject. Then add the dragged class to it, so that you can set the dragging style through CSS
When the user drags the element using the mouse or keyboard, the most complex part of the code is to track the position change. Then dX and dY (changes in X and Y) are given. Then add startX and startY to get the current position of the element.
The following function is used to set the position:
setPosition: function (dx,dy) {
dragDrop.draggedObject.style.left = dragDrop.startX dx 'px';
dragDrop.draggedObject.style.top = dragDrop.startY dy 'px';
},
The function uses the dX and dY calculated by mouse and keyboard movements and the initial position to set the new position of the element.
This part is very simple. The complicated part lies in the acquisition of dx and dy. The processing of the mouse part and the keyboard part are very different. Let's look at them separately.
Mouse part code
The calculation of the mouse part is more complicated than that of the keyboard, but there is no big problem in terms of browser compatibility. So we start with the mouse part.
Events
First let’s discuss events. Obviously, mousedown, mousemove, and mouseup are needed during the dragging process to complete the actions of selecting objects, dragging, and dragging.
This series of events starts with the mousedown event that requires dragging the element. So all drag elements need this event to indicate that dragging has started. We see:
element.onmousedown = dragDrop.startDragMouse;
However mousemove and mouseup events should not be set on elements but on the entire document. Because the user can move the mouse around quickly and frantically, and then lose the dragged element. If it is set on an element, it may be out of control because the mouse is not on the element, which is not a good thing for usability.
If we set mousemove and mouseup on the document, there will be no such problem. No matter where the mouse is, the element will respond to mousemove and mouseup. This is very easy to use.
Also you can only set mousemove and mouseup after dragging starts, and then delete them when the user releases the element. This code is very clean and saves system resources, because mousemove consumes a lot of system resources.
Mousedown
When a mousedown event occurs on a drag element, the startDragMouse function starts executing:
First the startDrag we discussed before will be executed. Then find the coordinates of the mouse and save them in initialMouseX and initialMouseY. We will compare the mouse position to this later.
Finally, false will be returned, which is used to prevent the default mouse event: selecting text. We no longer want text to be selected when dragging, which is annoying.
Then set mouseup and mousemove event handlers for the document. Since it's possible that the document has its own mouseup and mousemove event handlers, I use my addEventSimple function to prevent the original event handlers from failing.
Mousemove
Now, the dragMouse function is executed when the user moves the mouse.
dragMouse: function (e) {
var evt = e || window.event;
var dX = evt.clientX - dragDrop.initialMouseX;
var dY = evt.clientY - dragDrop.initialMouseY;
dragDrop.setPosition(dX,dY) ;
return false;
},
这个函数会读取鼠标现在的坐标,然后减去之前的坐标,把得到的dX和dY传递给sePosition。
然后通过返回false来阻止鼠标选择文本的默认属性。
Mouseup
当用户松开鼠标的时候,会调用releaseElement。我们后面讨论。
键盘部分代码
现在我们开始更复杂的键盘部分代码。不像鼠标拖拽那样,键盘拖拽并没有一个标准。虽说基本的交互不是太复杂,但是最好还是简要说明一下。
基本交互
用来拖拽的键最好是方向键,这很简单。
激活和释放元素是比较有技巧的,在这里我的代码还需要加强。
我觉得如果用键盘来激活的话就应该使用一个我添加的额外的链接。这里没有太多选择:因为链接能够在所有的浏览器里面获得焦点(好吧,表单也可以,你也可是选择复选框),而且把一个链接放置在可拖拽的元素里面也是合乎逻辑的(你可以放在任何地方,但是如何让用户知道那个是用来激活拖拽的呢?)。
我假设当用户点击enter或者Esc的时候释放元素,至少我没找到其他合适的键。你想选择其他的话可以在这里查找键盘代码。
case 13: // enter<br>case 27: // escape<br> dragDrop.releaseElement();<br> return false;
Copy after login
事件
点击可以激活元素。当鼠标点击链接或者当元素获得焦点的时候点击enter键就能激活。所以键盘代码的激活可以使点击enter键或者点击链接。
(严格来说,当你用鼠标点击链接的时候,元素先被鼠标事件激活然后释放了然后再被键盘模式激活。)
事件的其余部分也非常的模糊。当你想检测方向键的时候键盘事件尤为麻烦。
首先我们需要一个允许重复点击的事件,因为用户可能按着方向键不放,那么事件就需要一遍遍的触发,这样拖拽才能继续。所以我们使用keypress事件。
不幸的是,IE在keypress的情况下不支持方向键。在IE里面keydown会重复发生,看起来我们需要使用keydown事件了。
你可能才到事情没那么简单。在Opera和Safari里面keydown事件只能触发一次,所以当用户按下键之后,元素移动一次之后就不动了。在这些浏览器中我们需要keypress。
所以理想情况下,我们使用keypress,如果不支持就是用keydown。但是怎么切换事件呢?你又怎么知道keypress在这个时候不能用呢?
我的解决办法就是给keypress事件设置一个事件处理程序。如果这个程序执行了说明支持keypress,我们就可以安全的切换了。
startDragKeys函数用来设置keydown和keypress事件:
addEventSimple(document,'keydown',dragDrop.dragKeys);
addEventSimple(document,'keypress',dragDrop.switchKeyEvents);
首先keydown触发完成拖拽的dragKeys函数。这是第一个触发的事件,而且元素总会移动。然后我们做其他的话,那么元素在Opera和Safari1.3里面移动一次以后就会停止。
这就是为什么我们还需要keypress。第一个keypress事件会触发switchKeyEvents函数,这个函数会调整事件处理程序:
switchKeyEvents: function () {
removeEventSimple(document,'keydown',dragDrop.dragKeys);
removeEventSimple(document,'keypress',dragDrop.switchKeyEvents);
addEventSimple(document,'keypress',dragDrop.dragKeys);
},
他会先删除掉原来的事件处理程序,然后将keypress设置为触发dragKeys。因为这个函数只会在支持他的浏览器里面执行,所以我们只在这些浏览器里面将keydown改为keypress。
初始键盘代码
当用户点击了连接激活了元素,那么就会调用startDragKeys。
startDragKeys: function () {
dragDrop.startDrag(this.relatedElement);
dragDrop.dXKeys = dragDrop.dYKeys = 0;
addEventSimple(document,'keydown',dragDrop. dragKeys);
addEventSimple(document,'keypress',dragDrop.switchKeyEvents);
this.blur();
return false;
},
First it will Call the startDrag function we discussed earlier. He will pass relatedElement to this function, which is the element to be dragged.
Then set dXKeys and dYKeys to 0. These variables are used to track the displacement of elements.
Then set up the event handler, discussed above.
Then remove focus from the link you just clicked. I do this because the Enter key will release the element, but if the focus is not removed, when the user clicks the Enter key, the element is released, but the link is clicked again by Enter and becomes draggable again. If we remove the focus, the problem no longer exists.
Finally return false to prevent the default action.
Drag via keyboard
dragKeys are responsible for keyboard dragging:
dragKeys: function(e) {
var evt = e || window.event;
var key = evt.keyCode;
We first read the keyboard keys value.
Then we use a switch statement to decide what we do. The purpose of this part is to update the values of dXKeys and dYKeys, so that the element can be moved by setting its position.
switch (key) {
case 37: / / left
case 63234:
dragDrop.dXKeys -= dragDrop.keySpeed;
break;
case 38: // up
case 63232:
dragDrop.dYKeys -= dragDrop. keySpeed;
break;
case 39: // right
case 63235:
dragDrop.dXKeys = dragDrop.keySpeed;
break;
case 4 0: // down
case 63233:
dragDrop.dYKeys = dragDrop.keySpeed;
break;
The author determines the pixel size of each move by setting keySpeed. When the user clicks the left arrow key, keySpeed is subtracted.
This code contains the cases 63232-63235. Because Safari 1.3 does not use the standard 37-40 arrow key value (Safari 3 already supports it).
case 13: // enter
case 27: // escape
dragDrop.releaseElement();
return false;
If the user clicks the Enter or Esc key, the releaseElement() function is called. If you want to change the key to release the element, you can add it here.
default:
return true;
}
If the user presses another key, execute the default action and end the function.
dragDrop.setPosition(dragDrop.dXKeys,dragDrop.dYKeys) ;
Now that dXKeys and dYKeys have been updated we send them to the setPosition() function to change the position of the element.
if (evt.preventDefault)
evt.preventDefault ();
return false;
},
Finally we need to prevent the default event. If the user clicks the down arrow key, the page will scroll down after executing the above code. This is implemented by preventDefault in W3C compatible browsers and by returning false in IE.
Release element
When the user releases the element, the function releaseElement will be called. It will remove all event handlers set by the code, remove the dragged class, clean up the draggedObject and wait for user action.
releaseElement: function() {
removeEventSimple(document ,'mousemove',dragDrop.dragMouse);
removeEventSimple(document,'mouseup',dragDrop.releaseElement);
removeEventSimple(document,'keypress',dragDrop.dragKeys);
removeEventSimple(document,' keypress',dragDrop.switchKeyEvents);
removeEventSimple(document,'keydown',dragDrop.dragKeys);
dragDrop.draggedObject.className = dragDrop.draggedObject.className.replace(/dragged/,'');
DragDrop.draggedObject = null;
}
You may want to do something after the user releases the element, you can add your function here.
Translation address:
http://www.quirksmode.org/js/dragdrop.html Please keep the following information for reprinting
Author: Beiyu (tw:@rehawk)