写在开头
各位友友好吖❗
清明已过,下个期待的假期就是五一了,小长假即将到来,假期行程已经可以开始规划囖。😉
不过,对于是大小周的小编来说,整个四月都将是单休,瞬间开心减一半。。。
近来,小编断断续续抽空看了一部名叫 国王排名 动漫,还挺好看的。😁
还把几年不换的微信头像换成了主角的头像,Em……从”蜡笔小新”变成了”波吉王子”。
新头像,新心情,愉悦。😎
回到正题,本章将分享一些关于 Javascript
中拖动的内容,探索拖动过程的奥秘。👏
元素拖动
刚开始,咱们循序渐进,先来实现一个最简单的功能,让一个元素变成可拖动元素。
布局与样式:
1 | html复制代码<!DOCTYPE html> |
要让一个元素可拖动,我们需要处理三个事件:
三者都是老演员了,相信每个前端人都识得啦😋,具体详情可以点链接上MDN查阅。
具体逻辑过程:
1 | html复制代码<script> |
offsetTop:元素到 offsetParent
顶部的距离。
offsetParent:距离元素最近的一个具有定位的祖宗元素(relative,absolute,fixed
),若祖宗都不符合条件,offsetParent
为 body
。
效果:
大致原理过程:计算鼠标拖动的横向与纵向距离,再结合元素本身的 offsetTop
与 offsetLeft
信息,就能实现元素的拖动。
没几行代码,应该不难哈,都写上详细的注释啦。
上面用
clientX/Y
获取鼠标的位置信息,那用pageX/Y
可以不呢❓
clientX
:提供了鼠标指针相对于浏览器视口(即当前可见的页面部分)左上角的水平坐标。不论页面是否滚动,clientX
的值都是相对于视口的。
pageX
:提供了鼠标指针相对于整个页面左上角的水平坐标,包括了任何由于滚动而不可见的部分。当你滚动页面时,pageX
的值会改变,因为它考虑了滚动的距离。简而言之,就是要不要考虑滚动条的问题,如果你想要获取鼠标指针相对于整个页面的位置,应该使用
pageX
。如果你只关心鼠标指针在当前视口内的位置,那么clientX
就足够了。网上找了个图,可以瞧瞧:
列表拖动
简单的整完,咱们开始上点强度💀,这次要做的功能如下:
看着可能稍微有点复杂,但实际还好啦,我们一步一步来完成。
一样,先把布局与样式整一下:
1 | html复制代码<!DOCTYPE html> |
接下来,让每个元素变成可拖动元素。
1 | html复制代码<script> |
与前面讲的差不多,熟悉的配方。😗
稍微有一点区别是,将元素变成可拖动的逻辑与前面讲的不太一致了。😓
这里用上了 getBoundingClientRect API,其作用是为了优化前面在 mouseMoveHandler
函数中,需要不断去记录鼠标上一个位置的繁琐过程。
大概二者的区别如下:
1️⃣ 拖动元素的位置 = 拖动元素原本位置 + 拖动距离
2️⃣ 拖动元素的位置 = 根据鼠标最新位置直接计算拖动元素的最新位置 = 鼠标最新位置 - 鼠标在拖动元素上的距离
鼠标在拖动元素上的距离:
效果如下:
现在每个元素都能拖动了,只是还没有加上交换的逻辑。
但,这看着是不是有点奇怪?当拖动一个元素,列表下面的元素就顶上来了,这与咱们一开始看到的效果不太一致吖❗
这是因为缺少了一个占位元素,当在拖动元素时,需要自动插入一个占位元素,保持列表布局不会变化,拖动交换元素时,也应该是占位元素与其他元素进行交换,拖动结束时,再将占位元素给删除,将位置让给拖动元素。
下面,我们来看看如何解决这个占位元素的问题。
1 | javascript复制代码<!DOCTYPE html> |
加了大概十行代码,都是比较基础的DOM操作。👀
瞧瞧效果:
有那味了。🤡
最后,咱们差一步了,就是根据拖动方向进行元素之间的交换。
看到”拖动方向”加粗没😯?这是关键点,我们要如何知道拖动元素是往上还是往下呢❓并且交换元素位置的时机如何把握呢❓
看如下图,假设了中间三个元素的中心点坐标分别如下图。
当我们拖动第三个元素,往上,第三个元素的中心点坐标会不断变化,可能会变成(10,19)、(10,18)、(10,17)、……。
当继续往上拖动,第三个元素中心点坐标变成(10,9)时,它的纵坐标比第二个元素中心点纵坐标小了,这个时候就需要交换位置❗
根据这个原理过程,咱们先来写一个判断拖动方向的函数,如下:
1 | javascript复制代码// 检测拖动元素是否向上拖动 |
应该很好理解吧?🌟
交换元素的过程,咱们也可以单独写一个函数,如下:
1 | javascript复制代码// 交换两个相邻的元素位置 |
虽然只有短短四行代码,但这个时候就非常考验你的 Javascript
基础了。
(当然,这种东西你也可以直接问GPT,捡现成的。👻)
最后,结合具体逻辑:
1 | javascript复制代码function mouseMoveHandler() { |
我们仅需在 mouseMoveHandler
函数中添加交换逻辑即可。
这里要注意”占位元素要先与拖动元素交换位置”,可能你会有疑问?不是直接交换占位元素与上一个元素(或下一个元素)就行咩?😢
我们可以看看实际的DOM结构,第二个元素与占位元素中间还隔着拖动元素呢,注意我们是要交换两个相邻的元素,不是随便两个相隔遥远的元素哦。
好,到此完毕,列表拖动就完成啦。👻
表格拖动-列
接下来要做的是表格上的拖动,也是比较常见的功能了,话不多说,先看效果图:
做之前咱们先来分析一波,由于我们要拖动的是列,是竖着纵向排列的,而表格可是按照横向进行布局的❗
表格的布局结构:
1 | html复制代码<table id="table" class="table"> |
这…可不利于我们拖动处理呀❗我们要拖动的列必须是一个整体、是整个块,要是跨元素就麻烦了。
🌟这里咱们就要换个思路了,在要开始拖动时,动态创建一个纵向的列表,列表的每一子项就是表格的列,其实就是将表格转成我们上面已经讲过的列表拖动来进行操作;然后隐藏原表格,操作这个新列表,当拖动结束的时候,我们再通过列表的索引信息来交换表格的格子就行啦,是不是手拿把掐。😁(注意是拖动列表的项!!!)
那咱们先来看看如何动态创建出这个列表叭。😉
相关 HTML
结构就是上面那个表格布局了,没了。
相关 CSS
样式:
1 | html复制代码<!DOCTYPE html> |
上面列出了所有样式,对照着看看就行,样式不是重点,但是其中值得关注的是动态创建的列表,它的 border
是如何变成和表格的一样?因为稍微缺失一个格子的边框,可能就会造成列表和原表格不重合,容易露馅,这点你可以仔细琢磨一下。
1 | javascript复制代码<script> |
很熟悉吧,代码中很多都是前面讲过的了。
重点只有 createList
函数,它的作用就是创建一个与表格一样的列表,外观是一致的,只是与表格不同的是,它的布局是纵向的,就这么简单,详细的可以瞧瞧代码过程。👻
现在列表有了,操作列表的拖动这块咱熟呀,直接整上。
仅需改动 mouseMoveHandler
函数:
1 | javascript复制代码function mouseMoveHandler(e) { |
新增加的 swap
与 isOnLeft
函数在列表拖动的时候都讲过啦,这里就不多说了。
做到这里,你的表格(列表)应该是可以正常拖动了,只是拖动后的效果还能不真正同步到表格中而已,差最后一步,咱也给它加上、加上。😀
咱们仅需要改动 mouseUpHandler
函数,在拖动结束的时候将列表子项的索引信息同步回原表格上,然后把列表移除就可以了。
具体如下:
1 | javascript复制代码function mouseUpHandler() { |
应该不是很难哈,都写上了详细的注释。
好啦,就这么多,到此,咱们就完成了开头看到的表格列拖动的效果了。👻👻👻
表格拖动-行
既然讲了表格的列拖动了,那么行的拖动肯定也是不能落下啦。😁
不过现在我们有了前面的基础,这个不是洒洒水?有手就行?
HTML
结构不变。
CSS
样式略微调整一下:
1 | css复制代码... |
主要还是 JS
逻辑部分:
1 | javascript复制代码<script> |
大部分还是与上面讲过的一样,有一些略微差别而已,需要注意方向相关的就可以了。
还有就是动态创建的列表变成如下的样子了:
最后,放个效果图:
完整源码
传送门 👈👈👈
至此,本篇文章就写完啦,撒花撒花。
希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。
本文转载自: 掘金