探讨把一个元素从它所在的div 拖动到另一个div内的实现方法
故事背景:
接到一个新需求,要求用vue搞,主要是拖动实现布局,关键点有:单个组件拖动,一行多列里面的组件拖动, 单个组件可以拖入一行多列里, 单个组件的拖动好实现,关键是把一个组件拖动到另一个类似于表格里面,而且有的情况下还需要限制拖动只能在水平方向,自己搜集资料, 实验,终于搞出来了。
原理上主要分为两类:
- HTML5自带的拖放api,可用的库有 : Vue.Draggable
- 使用js 监听鼠标的移动位置, 可用的库有: jquery ui
- 使用point-event: none(下面会详细说明)
各自缺点
H5拖动的缺点:不能限制在水平 或垂直方向上拖动。
使用原生js缺点:大量的dom操作,代码复杂(jquery ui 封装的比较好了,可直接用)
但是问题来了,这次的需求是把基于jquery ui 的拖动 用 vue 重构,那么用vue.draggable吧, 但是需求里正好有一条是要限制在水平方向上拖动,尴尬,用不了。
寻找方案
最开始的尝试:
<!DOCTYPE html>
<html>
<head>
<title>vue结合原生js实现拖动</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<div class="ctn ctn1">
<div class="sub sub1" v-for="(site, index) in list1">
<div class="dragCtn fixed" :style="{ left: X+'px', top: Y+'px'}"
@mousedown="mousedown(site, $event)"
@mousemove.prevent='mousemove(site, $event)'
@mouseup='mouseup(site, $event)'>
拖动我
</div>
</div>
</div> <div class="ctn ctn2">
<div class="sub sub2" v-for="(site, index) in list2"
@mouseenter='mouseenter(site, $event)'>
<div class="dragCtn">
{{ index }} : {{ site.name }}
</div>
</div>
</div> </div> <script>
new Vue({
el: '#app',
data: {
list1: [{name:1, index:0}],
list2: [{name:'a', index:0}, {name:'b', index:1}, {name:'c', index: 2}, {name:'d', index: 3}],
vm:'',
sb_bkx: 0,
sb_bky: 0,
is_moving: false,
X: 0,
Y: 0
},
methods: {
mousedown: function (site, event) {
var startx=event.x;
var starty=event.y;
this.sb_bkx=startx - event.target.offsetLeft;
this.sb_bky=starty - event.target.offsetTop;
this.is_moving = true;
},
mousemove: function (site, event) {
var endx=event.x - this.sb_bkx;
var endy=event.y - this.sb_bky;
var _this = this
if(this.is_moving){
this.X = endx;
this.Y = endy;
}
},
mouseup: function (e) {
this.is_moving = false;
},
mouseenter: function (){
console.log('鼠标进入')
}
}
})
</script> <style>
.ctn{
line-height: 50px;
cursor: pointer;
font-size: 20px;
text-align: center;
float: left;
}
.sub:hover{
background: #e6dcdc;
color: white;
width: 100px;
}
.ctn1{
border: 1px solid green;
width: 100px;
}
.ctn2{
border: 1px solid black;
width: 100px;
margin-left: 50px;
}
.fixed{
width: 100px;
position: fixed;
background: red;
left: 0;
top: 0;
cursor: move;
}
</style>
</body>
</html>
就这样实现了基本的拖动,但是在拖动的时候,就不能触 mouseenter 事件了,而且鼠标必须拖动的很慢,移动快一点,拖动的div就跟不上了,这一点到现在还困惑,希望各位大侠指点。
然后在网上找了很多资料,类库,但是不能完全符合我的需求,于是准备自己写了;
首先是给组件添加mousedown事件,然后mousemove的时候 监听鼠标的位置,再赋值给组件,实现拖动,但是当组件拖动进入另一个元素的时候,无法监听mouseenter, 后来想的办法是给正在拖动的组件加上 point-event:none 属性,就是消除原有的鼠标事件,就可以触发其他组件的mouerenter事件了,point-event 属性的具体用法 可以参考这里:
www.zhangxinxu.com/wordpress/2…
因为拖动是用原生js写的,所以可以限制在水平方向拖动,再加上可以触发mouseenter事件,就正好实现的我的需求。
伪代码如下:
mousedown: function (event, site) {
document.onmousemove=function (ev) {
// 移动的时候给元素增加 point-event:none 属性
...
}
document.onmouseup=function (ev) {
// up的时候 要移除point-event属性
...
}
}
但是后来上面要求,要兼容ie10,由于 point-event:none 是H5的属性,于是我赶紧去看看兼容性, 可怕的事发生了,point-event 属性只兼容到 ie11,完蛋!
再想其他办法吧,没了思路,老版本的拖动是基于 jquery ui 的 ,于是去看了 jquery ui 的源码,看看它的拖动是怎么实现的。
jquery ui 拖动实现原理
不熟悉 jquery ui 的拖动方法的可以先看下 这里
看下面这段代码:
$(function() {
$( "#draggable" ).draggable();
$( "#droppable" ).droppable({
drop: function( event, ui ) {
$( this ).html( "Dropped!" );
}
});
});
之前的关键问题就是怎么判断拖动的元素 $( "#draggable" ) 在什么时候 进入了可以放置的区域 $( "#droppable" ) 的,看了源码,它的实现方式 简单来说就是拖动 $( "#draggable" ) 的时候监听 鼠标的位置, 同时获取 $( "#droppable" ) 的区域位置信息,只要鼠标进入该区域,就触发。
顺着这个思路,做了实验 可以满足自己的需求 good !
demo的实现效果如下:
代码地址:https://github.com/YalongYan/vue-drag-layout
拖动布局的实现方式应该还有更好的,欢迎大家提出更好的实现方式。
探讨把一个元素从它所在的div 拖动到另一个div内的实现方法的更多相关文章
- 让一个div拖动和让一个panel拖动加拉大拉小
一.让一个div拖动 <!doctype html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...
- css进阶 04-如何让一个元素水平垂直居中?
04-如何让一个元素水平垂直居中? #前言 老板的手机收到一个红包,为什么红包没居中? 如何让一个子元素在父容器里水平垂直居中?这个问题必考,在实战开发中,也应用得非常多. 你也许能顺手写出好几种实现 ...
- js 判断一个元素是否在滚动的可视区域内,不在就固定到可视区域的上方。
前言:最近工作中,有这样一个场景,判断一个元素是否在滚动的可视区域内,不在就固定到可视区域的上方.为了以后再次遇到,所以记录下来,并分享.转载请注明出处:https://www.cnblogs.com ...
- JS004. 获取数组最后一个元素且不改变数组的四种方法
TAG: Array.length Array.prototype.reverse() Array.prototype.slice() Array.prototype.pop() Array对象 - ...
- Javascript JQuery获取当前元素的兄弟元素/上一个/下一个元素(转)
var chils= s.childNodes; //得到s的全部子节点 var par=s.parentNode; //得到s的父节点 var ns=s.nextSbiling; //获得s的下一个 ...
- 每天php函数 - 数组最后一个元素取出
复制代码代码如下: $array=array(1,2,3,4,5); echo $array[count($array)-1];//计算数组长度,然后获取数组最后一个元素,如果数组中最后一个元素 ...
- [java]删除数组中的某一个元素
package org.company.project.test; import java.util.Arrays; import java.util.Scanner; public class Ar ...
- php 获取数组第一个元素 以及最后一个元素 && 最后一个元素的键名
1. current() 函数返回数组中的当前元素的值. 每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素. end() - 将内部指针指向数组中 ...
- 用jQuery判断一个元素的各种状态
用jQuery判断一个元素是否显示 用jQuery判断一个元素是否显示:$(element).is(":visible"); 类似的,判断一个元素是不是第一个子元素:$(ele ...
随机推荐
- ajax回调中window.open弹出的窗口会被浏览器拦截的解决方法
存在问题:处理页面ajax请求过程中,异步请求成功后需要新开窗口打开 url,使用的是 window.open() 方法 来实现,最终都被浏览器拦截了.不会跳到对应的页面,如下 原因:浏览器之所以拦截 ...
- [Android 新特性] 谷歌发布Android Studio开发工具1.0正式版(组图) 2014-12-09 09:35:40
Android Studio是谷歌于13年I/O大会推出的Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的Androi ...
- 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:3.安装Oracle RAC-3.5.安装oracle11gr2 database 软件与创建数据库
3.5.安装oracle11gr2 database 软件与创建数据库 3.5.1.安装Oracle 11gr2 Database 以oracle 用户登录到节点一,切换到软件安装目录,执行安装. 在 ...
- centos selinux学习记录
SELinux 全称 Security Enhanced Linux (安全强化 Linux),是 MAC (Mandatory Access Control,强制访问控制系统)的一个实现,目的在于明 ...
- oracle 10g函数大全--转换函数
chartorowid(c1) [功能]转换varchar2类型为rowid值 [参数]c1,字符串,长度为18的字符串,字符串必须符合rowid格式 [返回]返回rowid值 [示例] SELECT ...
- unity 部分obj不接受后处理
考虑了很多方案,比如渲染次序和mask(stencilebuffer) 渲染次序 sorting order(深度) renderer都有的属性能开放出来,sprite renderer原本就开放在i ...
- 处理 WebService 中的 Map 对象
最近,我们讨论了关于 WebService 的相关问题.目前在 Smart 中,可发布两种类型的 WebService,它们是:SOAP 服务 与 REST 服务,您可以根据需要自由选择. 今天,我要 ...
- 一起來玩鳥 Starling Framework(1)一定要的Hello World!
雖然已經一堆Hello World的介紹文章跟影片了,但中文資料畢竟是比較少,所以不能免俗的來一篇中文版Hello World.首先開啟一個AS3.0專案,fps不用客氣,設為60,Starling很 ...
- PHP+MYSQL的搭建
如今准备研究下微信的开发,所以要研究下PHP了,但对这个平台还是非常陌生的,所以网上找了些资料并測试,现贴出来给大家參考. 第一步:我们先下载[PHPStudy 2013]或者最新版本号: 下载地址: ...
- 从webstorm转vscode,来一个vscode的教程和心得总结
背景 在公司跑代码,每天卡的吐血,感觉生命都被浪费了. 再在摧残了一段时间,天天想摔电脑以后,被同事安利vscode, 那就开始搞起来 安装 这个我真的不用说了吧 插件 快捷键 shift + alt ...