原生js 元素拖拽动态排序

您所在的位置:网站首页 html元素拖拽 原生js 元素拖拽动态排序

原生js 元素拖拽动态排序

2023-05-28 14:06| 来源: 网络整理| 查看: 265

效果

github地址

基础版

在这里插入图片描述

class封装页面版

在这里插入图片描述

拖拽html

1、使用拖拽事件的时候,报错‘Cannot set property ‘ondragstart’ of null’:

原因:JS的引进放在了head标签里面,浏览器遇到标签的时候会立即执行脚本,这个时候DOM树还没有构建完成,访问不到节点

解决:

把JS的引进放在body标签底部 使用’defer’异步加载js文件,不会影响DOM渲染,js脚本会在DOM渲染完毕后,DOMContentLoaded事件调用前执行 defer和async: async也是异步加载js文件,区别在于async还是异步执行js文件,先加载完的脚本先执行。(适用于不关心DOM元素的脚本)

拖拽事件

拖动目标: ondragstart:开始拖动 ondrag:正在拖动 ondragend:完成拖动

释放目标: ondragenter:拖动对象进入容器范围 ondragover:拖动对象在另一容器范围内拖动 ondragleave:拖动对象离开容器范围 ondrop:拖动过程中释放鼠标

插入元素

DOM的insertBefore()方法:把一个新元素插到一个现有元素的前面

parentElement.insertBefore(newElement,targetElement)

实现在一个现有元素后面插入新元素: nextSibling —> 下一个兄弟元素,若没有则为null 把新元素插到目标元素的下一个兄弟元素前面,如果下一个兄弟元素为null将被插到子节点的末尾

parentElement.insertBefore(newElement,targetElement.nextSibling)

css3动画

1、获取元素位置 getBoundingClientRect()用于获取页面中某元素的左右上下分别相对浏览器视窗的位置

2、node.nodeType 判断节点类型。如果节点是元素节点返回1,如果是属性节点返回2

3、transform:translate3d(0,0,0) 触发加速,使GPU适应CSS过渡,更加流畅

4、target.offsetWidth 通过获取元素的offsetWidth或者offsetHeight触发重绘。

1、判断元素是否在动画中,防止重复动画 在拖动的时候,dragover是会不停触发的,导致过多的加载动画,所以需要判断元素是否已经添加动画,可以设置一个定时器,在事件到了之后将transition和transform清空

if (target.animated) { return } target.animated = setTimeout(function() { _css(target, 'transition', ''); _css(target, 'transform', ''); target.animated = false; }, ms); 代码 拖拽排序 ul { list-style: none; margin: 200px; font-size: 0; } .ele { font-size: 16px; width: 100px; height: 40px; border: 1px solid #999; background: #EA6E59; margin: 2px 0; border-radius: 10px; padding-left: 10px; color: white; cursor: move; } Document 1 2 3 4 5 6 7 8 var node = document.querySelector("#container") var draging = null node.ondragstart = function(event) { console.log("start:") // dataTransfer.setData把拖动对象的数据存入其中,可以用dataTransfer.getData来获取数据 event.dataTransfer.setData("te", event.target.innerText) draging = event.target } node.ondragover = function(event) { console.log("over:") // 默认地,无法将数据/元素放置到其他元素中。如果需要设置允许放置,必须阻止对元素的默认处理方式 event.preventDefault() var target = event.target if (target.nodeName === "LI" && target !== draging) { // 获取初始位置 var targetRect = target.getBoundingClientRect() var dragingRect = draging.getBoundingClientRect() if (target) { // 判断是否动画元素 if (target.animated) { return; } } if (_index(draging) // 目标比元素小,插到其前面 target.parentNode.insertBefore(draging, target) } _animate(dragingRect, draging) _animate(targetRect, target) } } // 获取元素在父元素中的index function _index(el) { var index = 0 if (!el || !el.parentNode) { return -1 } // previousElementSibling:上一个兄弟元素 while (el && (el = el.previousElementSibling)) { index++ } return index } // 触发动画 function _animate(prevRect, target) { var ms = 300 if (ms) { var currentRect = target.getBoundingClientRect() 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; // 触发重绘 _css(target, 'transition', 'all ' + ms + 'ms'); _css(target, 'transform', 'translate3d(0,0,0)'); // 事件到了之后把transition和transform清空 clearTimeout(target.animated); target.animated = setTimeout(function() { _css(target, 'transition', ''); _css(target, 'transform', ''); target.animated = false; }, ms); } } // 给元素添加style function _css(el, prop, val) { var style = el && el.style if (style) { if (val === void 0) { 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') } } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3