在我的项目中使用过vue.draggable这个插件,用来做拖拽,它是封装Sortable这个插件的。
各位大爷们,传送门我放这:
github.com/SortableJS/…
github.com/SortableJS/…
我做项目没有看过其源码,说起它的原理来也是靠猜的,今天我网上去下载下源码来,看了半个小时,两眼一抹黑,更懵了。
然后我就网上去找拖拽改变顺序的原理,万能的搜索引擎,我找到了这个大佬写的,拿来看了,方才如梦初醒。各位大爷,链接给你们放下面了。
www.jianshu.com/p/a923add40…
我把他的代码拷贝下来,运行了下,看了看,自己照着写了写,谢谢作者大佬。谢谢大哥精简的代码,让我明白了其实现原理。厉害,厉害,谢谢!谢谢!谢谢!
如果有侵权,我立即删了
虽然赶不上人家,不过,胡适说过:
怕什么真理无穷,进一寸有一寸的欢喜。
我之前想得很复杂,如何判断拖拽后的元素位于什么位置,如何去改变顺序,想来想去,更没有办法下笔了。各位大爷们,完整渣渣代码我贴在最后,我把我觉得核心的拿出来讲讲。还是带着问题去看吧。
- 靠哪个属性进行拖拽?
- 怎么判断拖拽到哪个位置了?
- 怎么交换顺序?
1、靠哪个属性值进行拖拽
利用h5的拖拽属性draggable,配合相应的事件ondragstart和ondragover来实现拖拽。
2、怎么判断拖拽到哪个位置了
首先被拖拽的目标元素dragObj,经过每一个子元素item时候,都会触发其dragover事件。
可以利用一个函数,来计算item在父元素的的index值。经过该元素时候,计算item和dragObj的index值,然后利用dom的insertBefore来把dragObj插入到该元素上面或者下面。
判断index大小主要用来判断是在item的上面插入还是下面插入。
3、怎么交换顺序
交换顺序主要是使用了dom的insertBefore,它是插入和改变dom节点的api,各位大爷,链接我放这:
www.w3school.com.cn/jsref/met_n…
所以,说了那么多,那个获取index的函数怎么写?
// 获取元素所在数组的当前index
function _index(el) {
var index = 0;
if (!el || !el.parentNode) {
return -1;
}
// 反复寻找它有几个前兄弟元素
// previousElementSibling 属性返回指定元素的前一个兄弟元素,循环遍历之前的所有兄弟节点
while (el && (el = el.previousElementSibling)) {
// console.log(el);
index++;
// console.log('--while---',el,index);
}
// console.log(index)
return index;
}
最后,
关键:一个属性,一个变量,两个事件,一个函数,一个dom的api。
一个属性:draggable="true"
一个变量:用来存放被拖拽的元素dragObj
两个事件:ondragstart,ondragover
一个函数:计算元素处于父元素的子元素数组里面的哪个index
一个dom的api:insertBefore
思路:
1、给被拖拽的子元素加上draggable="true"属性,
2、父元素绑定ondragstart和ondragover事件,
3、dragstart的时候,把被拖拽的元素赋值存起来为dragObj,
4、每个被经过的子元素target都会有dragover事件,
5、在dragover事件里,利用获取index的函数,判断被拖拽元素dragObj和target元素的index的大小
6、在taget的nextSibing或者taget自己利用insertBefore插入dragObj。
最后:
这个版本是乞丐版本,各位大爷们将就下哈。我后续还会接着啃vue.draggable源码,给各位看官用口水话讲出来,方便理解,我还会继续更新拖拽方面的内容,这只是一个开始。
最后渣渣代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.item {
width: 100%;
height: 50px;
border: 1px solid red;
}
</style>
</head>
<body>
<div id="ordered-container"> </div>
<script>
var data = [
{ label: "Item 1" },
{ label: "Item 2" },
{ label: "Item 3" },
{ label: "Item 4" },
{ label: "Item 5" },
{ label: "Item 6" }]
setupOrderedContainers();
function setupOrderedContainers() {
// 先渲染列表
var container = document.querySelector("#ordered-container");
var html = '';
data.forEach(item => {
html+=`<div class="item" draggable="true">
${item.label}
</div>`;
})
container.innerHTML = html;
var drag = null;
// 拖拽开始,赋值
container.ondragstart = function (event) {
drag = event.target;
}
// 拖拽过程中,插入元素
container.ondragover = function (event) {
var target = event.target;
// console.log('--ondragover---', _index(drag), _index(target))
if(_index(drag) < _index(target)) {
// 向下拖拽
// console.log('向下拖拽');
target.parentNode.insertBefore(drag, target.nextSibing);
} else {
// console.log('向上拖拽');
target.parentNode.insertBefore(drag, target);
}
}
}
// 获取元素所在数组的当前index
function _index(el) {
var index = 0;
if (!el || !el.parentNode) {
return -1;
}
// 反复寻找它有几个前兄弟元素
// previousElementSibling 属性返回指定元素的前一个兄弟元素,循环遍历之前的所有兄弟节点
while (el && (el = el.previousElementSibling)) {
// console.log(el);
index++;
// console.log('--while---',el,index);
}
// console.log(index)
return index;
}
</script>
</body>
</html>
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!