js实现拖动排序
先介紹一下html5的drag屬性,拖放(Drag 和 drop)是 HTML5 標準的組成部分。想要啟用drag,只要給元素加上draggable="true"就行了(Safari 5.1.2除外)。
實現效果
js拖動排序
拖動事件
??事件分為兩類,當前拖動的元素上的事件,以及要放置的位置接收到的事件。
??一.發生在拖動元素上的事件:
二.發生在目標元素上的事件
事件名 觸發時機 觸發次數 dragenter 當拖動元素進入目標時觸發一次 1 dragover 當拖動元素在目標元素范圍內時反復觸發 n drop 拖動元素在目標元素內釋放時(在設置了dropover事件的前提下) 1信息傳遞
在拖動元素時可以設置傳遞的信息 event.dataTransfer.setData(“te”, “sss); 兩個參數,第一個參數key,第二個參數value。 注意只能傳遞字符串和url,但是在firefox使用text或Text作為key時會打開新的標簽頁,所以不要用他們作為key。注意:設置了dragover后drop才會觸發!!
下面是html代碼:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>*{list-style: none;margin: 0;padding: 0;}#container{width: 500px;margin: 100px auto;}.ele {width:100%;height: 40px;border: 1px solid #999;background: cadetblue;margin-top: 2px;border-radius: 10px;padding-left: 10px;color: white;cursor: move;}</style> </head> <body> <ul id="container"><li class="ele" draggable="true">1</li><li class="ele" draggable="true">2</li><li class="ele" draggable="true">3</li><li class="ele" draggable="true">4</li> </ul> <script>var node = document.querySelector("#container");var draging = null;//使用事件委托,將li的事件委托給ulnode.ondragstart = function(event) {//console.log("start");//firefox設置了setData后元素才能拖動!!!!//event.target出發事件的元素event.dataTransfer.setData("te", event.target.innerText); //不能使用text,firefox會打開新tab//event.dataTransfer.setData("self", event.target);draging = event.target;console.log(draging,'aaaa');}node.ondragover = function(event) {//console.log("onDrop over");//取消默認行為event.preventDefault();var target = event.target;//因為dragover會發生在ul上,所以要判斷是不是liif (target.nodeName === "LI") {if (target !== draging) {//getBoundingClientRect()用于獲取某個元素相對于視窗的位置集合var targetRect = target.getBoundingClientRect();var dragingRect = draging.getBoundingClientRect();if (target) {if (target.animated) {return;}}if (_index(draging) < _index(target)) {//nextSibling 屬性可返回某個元素之后緊跟的節點(處于同一樹層級中)。target.parentNode.insertBefore(draging, target.nextSibling);} else {target.parentNode.insertBefore(draging, target);}_animate(dragingRect, draging);_animate(targetRect, target);}}}//獲取元素在父元素中的indexfunction _index(el) {var index = 0;if (!el || !el.parentNode) {return -1;}//previousElementSibling屬性返回指定元素的前一個兄弟元素(相同節點樹層中的前一個元素節點)。while (el && (el = el.previousElementSibling)) {//console.log(el);index++;}return index;}function _animate(prevRect, target) {var ms = 300;if (ms) {var currentRect = target.getBoundingClientRect();//nodeType 屬性返回以數字值返回指定節點的節點類型。1=元素節點 2=屬性節點if (prevRect.nodeType === 1) {prevRect = prevRect.getBoundingClientRect();}_css(target, 'transition', 'none');_css(target, 'transform', 'translate3d(' +(prevRect.left - currentRect.left) + 'px,' +(prevRect.top - currentRect.top) + 'px,0)');target.offsetWidth; // 觸發重繪//放在timeout里面也可以// setTimeout(function() {// _css(target, 'transition', 'all ' + ms + 'ms');// _css(target, 'transform', 'translate3d(0,0,0)');// }, 0);_css(target, 'transition', 'all ' + ms + 'ms');_css(target, 'transform', 'translate3d(0,0,0)');clearTimeout(target.animated);target.animated = setTimeout(function() {_css(target, 'transition', '');_css(target, 'transform', '');target.animated = false;}, ms);}}//給元素添加stylefunction _css(el, prop, val) {var style = el && el.style;if (style) {if (val === void 0) {//使用DefaultView屬性可以指定打開窗體時所用的視圖if (document.defaultView && document.defaultView.getComputedStyle) {val = document.defaultView.getComputedStyle(el, '');} else if (el.currentStyle) {val = el.currentStyle;}return prop === void 0 ? val : val[prop];} else {if (!(prop in style)) {prop = '-webkit-' + prop;}style[prop] = val + (typeof val === 'string' ? '' : 'px');}}} </script> </body> </html>下面是在組件中的代碼:
index.tsx
import React, { useEffect, useState } from 'react' import './index.less' export default function DragSotr() {const [list] = useState([{ id: "1", name: "1" },{ id: "2", name: "2" },{ id: "3", name: "3" },{ id: "5", name: "5" },])useEffect(() => {// 獲取dom節點let list = document.querySelector('.container')// 滑動domlet draging = null// 拖動開始list.ondragstart = function (event) {// console.log("。。。。", event.target);//dataTransfer專門用來存儲拖放時要攜帶的數據//setData有兩個參數:// 1.第一個參數為攜帶數據的數據種類的字符串,只能填入類 似“text/plain”或“textml”的表示 MIME類型的文字// 2.第二個參數為要攜帶的數據event.dataTransfer.setData("te", event.target.innerText); //不能使用text,firefox會打開新tabdraging = event.target; //滑動新的節點}//獲取元素在父元素中的indexfunction _index(el) {var index = 0;if (!el || !el.parentNode) {return -1;}//previousElementSibling屬性返回指定元素的前一個兄弟元素(相同節點樹層中的前一個元素節點)。while (el && (el = el.previousElementSibling)) {index++;}return index;}//給元素添加stylefunction _css(el, prop, val) {var style = el && el.style;if (style) {if (val === 0) {//使用DefaultView屬性可以指定打開窗體時所用的視圖if (document.defaultView && document.defaultView.getComputedStyle) {val = document.defaultView.getComputedStyle(el, '');} else if (el.currentStyle) {val = el.currentStyle;}return prop === 0 ? val : val[prop];} else {if (!(prop in style)) {prop = '-webkit-' + prop;}style[prop] = val + (typeof val === 'string' ? '' : 'px');}}}//滑動function _animate(prevRect, target) {var ms = 300;if (ms) {var currentRect = target.getBoundingClientRect();//nodeType 屬性返回以數字值返回指定節點的節點類型。1=元素節點 2=屬性節點if (prevRect.nodeType === 1) {prevRect = prevRect.getBoundingClientRect();}_css(target, 'transition', 'none');_css(target, 'transform', 'translate3d(' +(prevRect.left - currentRect.left) + 'px,' +(prevRect.top - currentRect.top) + 'px,0)');target.offsetWidth; // 觸發重繪//放在timeout里面也可以// setTimeout(function() {// _css(target, 'transition', 'all ' + ms + 'ms');// _css(target, 'transform', 'translate3d(0,0,0)');// }, 0);_css(target, 'transition', 'all ' + ms + 'ms');_css(target, 'transform', 'translate3d(0,0,0)');clearTimeout(target.animated);target.animated = setTimeout(function () {_css(target, 'transition', '');_css(target, 'transform', '');target.animated = false;}, ms);}}list.ondragover = function (event) {//取消默認行為event.preventDefault();var target = event.target;//因為dragover會發生在ul上,所以要判斷是不是liif (target.nodeName === "LI") {if (target !== draging) {//getBoundingClientRect()用于獲取某個元素相對于視窗的位置集合var targetRect = target.getBoundingClientRect();var dragingRect = draging.getBoundingClientRect();if (target) {if (target.animated) {return;}}if (_index(draging) < _index(target)) {//nextSibling 屬性可返回某個元素之后緊跟的節點(處于同一樹層級中)。target.parentNode.insertBefore(draging, target.nextSibling);} else {target.parentNode.insertBefore(draging, target);}_animate(dragingRect, draging);_animate(targetRect, target);}}}}, [])return (<ul className="container">{/* <li className="ele" draggable="true">1</li><li className="ele" draggable="true">2</li><li className="ele" draggable="true">3</li><li className="ele" draggable="true">4</li> */}{list.map((item, index) => {return <li className="ele" draggable="true" key={index}>{item.name}</li>})}</ul>) }index.less
.container {height: 100vh;list-style: none;.ele {width: 100px;height: 10px;background: cadetblue;margin-top: 2px;color: white;cursor: move;line-height: 10px;text-align: center;} }總結
- 上一篇: 超详细讲解搭建guacamole实现远程
- 下一篇: 吃完饭了