jQuery 移动端拖拽(模块化开发,触摸事件,webpack)


Posted in Javascript onOctober 28, 2016

通过jquery可以很容易实现CP端的拖拽。但是在移动端却不好用了。于是我自己写了一个在移动端的拖拽demo,主要用到的事件是触摸事件(touchstart,touchmove和touchend)。

这个demo实现的功能是:可以拖拽的元素(在这里是图片)位于列表中,这些元素可以被拖到指定区域,到达指定区域(控制台)后,元素被插入控制台后,原来的拖动元素返回原位置,新的元素依然可以在控制台中拖动,也能拖出控制台。

在这个demo中一个用三个模块,分别为ajax模块,drag模块,position模块。ajax模块用于实现ajax请求(所以的图片资源是通过ajax请求得到的),drag模块用于实现元素拖拽,position模块用于实现元素位置的操作(如位置初始化,复原,移除)。demo的入口文件是indx.js和前面三个模块文件保存在同一个文件夹中。编码完成后通过webpack打包。开发代码位于app文件夹中,打包后的代码位于build文件夹中。

一.触摸事件的介绍

触摸事件有三个,分别是touchstart,touchmove和touchend。touchstart事件在手指触摸屏幕时触发。touchmove当手指在屏幕上滑动时连续触发。在这个事件发生期间取消它的默认,可以组织页面滚动。touchend在手指从屏幕上离开时触发。这三个触摸事件的事件对象除了提供了鼠标事件的常见属性,还包含了下面三个属性:

touches:表示当前跟踪的触摸操作的touch对象的数组。

targetTouches:特定于事件目标的Touch对象的数组。

changeTouches:表示自上次触摸以来发生了什么改变的Touch对象的数组。

在这个案例中需要得到触摸点相对视口的位置,我使用的是event.targetTouches[0].clientX和event.targetTouches[0].clientY

二.ajax模块的代码

var $ = require('jquery');
var ajax = {
//得到可拖拽图片的初始列表
getInitImg:function(parent){
var num = 50;
$.ajax({
type:"GET",
async:false,//这里使用同步加载,因为要让图片加载完成后才能做其他操作
url:'/Home/picwall/index',
success:function(result){
if(result.status == 1) {
$.each(result.data, function (index,item) {
var src = item.pic_src;
var width = parseInt(item.width);
var height = parseInt(item.height);
var ratio = num / height;
var img = $('').attr("src",src).height(num).width(parseInt(width * ratio));
parent.append(img);
});
}
},
dataType:'json'
});
}
};
module.exports = ajax;//将ajax模块暴露出来

三.position模块的代码

var $ = require('jquery');
var position = {
//初始化位置,gap是一个表示元素间距的对象
init:function(parent,gap){
var dragElem = parent.children();
//确保父元素是相对定位
if(parent.css('position') !== "relative"){
parent.css('position','relative');
}
parent.css({
'width':"100%",
'z-index':'10'
});
//当前列表内容的宽度
var ListWidth = 0;
//位于第几列
var j = 0;
dragElem.each(function(index,elem){
var curEle = $(elem);
//设置元素的初始位置
curEle.css({
position:"absolute",
top:gap.Y,
left:ListWidth + gap.X
});
//为每个元素添加一个唯一的标识,在恢复初始位置时有用
curEle.attr('index',index);
//将元素的初始位置保存起来
position.coord.push({
X:ListWidth + gap.X,
Y:gap.Y
});
j++;
//设置父元素的高度
parent.height( parseInt(curEle.css('top')) + curEle.height() + gap.Y);
ListWidth = curEle.offset().left + curEle.width();
});
},
//将子元素插入到父元素中
addTo:function(child,parent,target){
//父元素在视口的坐标
var parentPos = {
X:parent.offset().left,
Y:parent.offset().top
};
//目标位置相对于视口的坐标
var targetPos = {
X:target.offset().left,
Y:target.offset().top
};
//确保父元素是相对定位
if(parent.css('position') !== "relative"){
parent.css({
'position':'relative'
});
}
parent.css({
'z-index':'12'
});
//将子元素插入父元素中
parent.append(child);
//确定子元素在父元素中的位置并且保证子元素的大小不变
child.css({


 position:absolute,
top:targetPos.Y - parentPos.Y,
left:targetPos.X - parentPos.X,
width:target.width(),
height:target.height()
});
},
//将元素恢复到原来的位置
restore:function(elem){
//获得元素的标识
var index = parseInt( elem.attr('index') );
elem.css({
top:position.coord[index].Y,
left:position.coord[index].X
});
},
//拖拽元素的初始坐标
coord:[],
//判断元素A是否在元素B的范围内
isRang:function(control,dragListPar,$target){
var isSituate = undefined;
if(control.offset().top > dragListPar.offset().top){
isSituate = $target.offset().top > control.offset().top
&& $target.offset().left > control.offset().left
&& ($target.offset().left + $target.width()) < (control.offset().left + control.width());
}else{
isSituate = ($target.offset().top + $target.height())<(control.offset().top + control.height())
&& $target.offset().top > control.offset().top
&& $target.offset().left > control.offset().left
&& ($target.offset().left + $target.width()) < (control.offset().left + control.width());
}
return isSituate;
}
};
module.exports = position;

四.drag模块的代码

var $ = require('jquery');
var position = require('./position.js');
var drag = {
//拖拽元素的父元素的id
dragParen:undefined,
//操作台的id值
control:undefined,
//移动块相对视口的位置
position:{
X:undefined,
Y:undefined
},
//触摸点相对视口的位置,在滑动过程中会不断更新
touchPos:{
X:undefined,
Y:undefined
},
//开始触摸时触摸点相对视口的位置
startTouchPos:{
X:undefined,
Y:undefined
},
//触摸点相对于移动块的位置
touchOffsetPos:{
X:undefined,
Y:undefined
},
//获取拖拽元素父元素id和控制台的ID的值
setID:function(dragList,control){
this.dragParent = dragList;
this.control = control;
},
touchStart:function(e){
var target = e.target;
//阻止冒泡
e.stopPropagation();
//阻止浏览器默认的缩放和滚动
e.preventDefault();
var $target = $(target);
//手指刚触摸到屏幕上时,触摸点的位置
drag.startTouchPos.X = e.targetTouches[0].clientX;
drag.startTouchPos.Y = e.targetTouches[0].clientY;
//触摸元素相对视口的位置
drag.position.X = $target.offset().left;
drag.position.Y = $target.offset().top;
//触摸点相对于视口的位置,滑动过程中不断更新
drag.touchPos.X = e.targetTouches[0].clientX;
drag.touchPos.Y = e.targetTouches[0].clientY;
//触摸点相对于触摸元素的位置
drag.touchOffsetPos.X = drag.touchPos.X - drag.position.X;
drag.touchOffsetPos.Y = drag.touchPos.Y - drag.position.Y;
//给目标元素绑定touchMove事件
$target.unbind('touchmove').on('touchmove',drag.touchMove);
},
touchMove:function(e){
var target = e.target;
//阻止冒泡
e.stopPropagation();
//阻止浏览器默认的缩放和滚动
e.preventDefault();
var $target = $(target);
//获得触摸点的位置
drag.touchPos.X = e.targetTouches[0].clientX;
drag.touchPos.Y = e.targetTouches[0].clientY;
//修改移动块的位置
$target.offset({
top: drag.touchPos.Y - drag.touchOffsetPos.Y,
left: drag.touchPos.X - drag.touchOffsetPos.X
});
//给移动元素绑定touchend事件
$target.unbind('touchend').on('touchend',drag.touchEnd);
},
touchEnd:function(e) {
var target = e.target;
//阻止冒泡
e.stopPropagation();
//阻止浏览器默认的缩放和滚动
e.preventDefault();
var $target = $(target);
var parent = $target.parent();
//得到控制台和拖动元素列表的父元素
var control = $("#" + drag.control);
var dragListPar = $('#' + drag.dragParent);
//拖动元素是否位于控制台
var sitControl = position.isRang(control, dragListPar, $target);
//拖动结束后,如果拖拽元素的父元素是拖拽列表
if (parent.attr('id') === drag.dragParent) {
//如果元素位于控制台
if (sitControl) {
var dragChild = $target.clone();
//为克隆出的元素绑定touchstart事件
dragChild.unbind('touchstart').on('touchstart',drag.touchStart);
//将克隆出的元素插入到控制台
position.addTo(dragChild, control, $target);
}
//将原来的触摸元素恢复到初始位置
position.restore($target);
}
// 拖拽结束后,如果拖拽元素的父元素是控制台,并且元素拖出了控制台
if (parent.attr('id') === drag.control && !sitControl) {
$target.remove();
}
}
};
module.exports = drag;

五.入口文件index.js的代码

require('../css/base.css');
require('../css/drag.css');
var $ = require('jquery');
var drag = require('./drag.js');
var position = require('./position.js');
var ajax = require('./ajax.js');
var dragList = $('#dragList');
//可拖拽元素的水平,竖直间距
var gap = {
X:20,
Y:10
};
//通过ajax获取可拖拽的元素的列表
ajax.getInitImg(dragList);
//初始化可拖拽元素的位置
position.init(dragList,gap);
//设置控制台的高度。控制台的高度为屏幕的高度减去拖拽列表的盖度
var control = $('#control');
control.height( $(window).height() - dragList.height() );
//给每个拖动元素绑定touchstart事件
var dragElem = dragList.children();
dragElem.each(function(index,elem){
$(elem).unbind('touchstart').on('touchstart',drag.touchStart);
});
//拖拽元素的父元素的id值为dragList,操作台的id值为control
drag.setID('dragList','control');

六.webpack打包

上面用到了模块化编程的思想,将不同的功能实现写在了不同的模块中,需要用到什么功能就可以用require()去引入,但是浏览器并没有require方法的定义。所以上面的代码并不能直接在浏览器中运行,需要先打包。如果你对webpack还不熟悉你可以去查看这篇文章,webpack的配置文件如下:

var autoHtml = require('html-webpack-plugin');
var webpack = require('webpack');
var extractTextWebpack = require('extract-text-webpack-plugin');// 这个插件可以将css文件分离出来,为css文件位于单独的文件中
module.exports = {
entry:{
'index':'./app/js/index.js',
'jquery':['jquery']
},
output:{
path:'./build/',
filename:'js/[name].js'
},
module:{
loaders:[
{
test:/\.css/,
loader:extractTextWebpack.extract('style','css')
}
]
},
plugins:[
new extractTextWebpack('css/[name].css',{
allChunks:true
}),
new webpack.optimize.CommonsChunkPlugin({
name:'jquery',
filename:'js/jquery.js'
}),
new autoHtml({
title:"拖拽",
filename:"drag.html",
template:'./app/darg.html',
inject:true
})
]
};

以上所述是小编给大家介绍的jQuery 移动端拖拽(模块化开发,触摸事件,webpack),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
仿jQuery的siblings效果的js代码
Aug 09 Javascript
setTimeout和setInterval的深入理解
Nov 08 Javascript
JS动态添加与删除select中的Option对象(示例代码)
Dec 20 Javascript
两种方法实现在HTML页面加载完毕后运行某个js
Jun 16 Javascript
Bootstrap中的Panel和Table全面解析
Jun 13 Javascript
jQuery post数据至ashx实例详解
Nov 18 Javascript
js清除浏览器缓存的几种方法
Mar 15 Javascript
Easyui Datagrid自定义按钮列(最后面的操作列)
Jul 13 Javascript
ES6学习教程之对象字面量详解
Oct 09 Javascript
JS实现DOM节点插入操作之子节点与兄弟节点插入操作示例
Jul 30 Javascript
Vue 通过自定义指令回顾v-内置指令(小结)
Sep 03 Javascript
js实现弹框效果
Mar 24 Javascript
RequireJS简易绘图程序开发
Oct 28 #Javascript
jquery配合.NET实现点击指定绑定数据并且能够一键下载
Oct 28 #Javascript
微信小程序 页面跳转传参详解
Oct 28 #Javascript
微信小程序 wx:key详细介绍
Oct 28 #Javascript
微信小程序 使用picker封装省市区三级联动实例代码
Oct 28 #Javascript
基于Layer+jQuery的自定义弹框
May 26 #Javascript
微信开发 js实现tabs选项卡效果
Oct 28 #Javascript
You might like
thinkphp文件引用与分支结构用法实例
2014/11/26 PHP
简单谈谈PHP vs Node.js
2015/07/17 PHP
PHP读取并输出XML文件数据的简单实现方法
2017/12/22 PHP
PDO::errorCode讲解
2019/01/28 PHP
PHP strripos函数用法总结
2019/02/11 PHP
jquery select下拉框操作的一些说明
2010/04/02 Javascript
利用google提供的API(JavaScript接口)获取网站访问者IP地理位置的代码详解
2010/07/24 Javascript
推荐JavaScript实现继承的最佳方式
2014/11/11 Javascript
jQuery Ajax中的事件详细介绍
2015/04/16 Javascript
JS集成fckeditor及判断内容是否为空的方法
2016/05/27 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
Javascript中for循环语句的几种写法总结对比
2017/01/23 Javascript
Vue中引入样式文件的方法
2017/08/18 Javascript
全新打包工具parcel零配置vue开发脚手架
2018/01/11 Javascript
js实现动态改变radio状态的方法
2018/02/28 Javascript
JavaScript引用类型Date常见用法实例分析
2018/08/08 Javascript
Vue实现拖放排序功能的实例代码
2019/07/08 Javascript
Vue Cli3 打包配置并自动忽略console.log语句的方法
2020/04/23 Javascript
[58:35]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.22
2019/09/05 DOTA
python 队列详解及实例代码
2016/10/18 Python
简单谈谈python中的多进程
2016/11/06 Python
Django ORM多对多查询方法(自定义第三张表&amp;ManyToManyField)
2019/08/09 Python
Pytorch 神经网络—自定义数据集上实现教程
2020/01/07 Python
pytorch 模拟关系拟合——回归实例
2020/01/14 Python
python中如何使用虚拟环境
2020/10/14 Python
用CSS3来实现社交分享按钮
2014/11/11 HTML / CSS
HTML5 Canvas实现玫瑰曲线和心形图案的代码实例
2014/04/10 HTML / CSS
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
关于.NET, HTML的五个问题
2012/08/29 面试题
社区道德讲堂实施方案
2014/03/21 职场文书
合作协议书
2014/04/23 职场文书
学校安全工作汇报材料
2014/08/16 职场文书
给上级领导的感谢信
2015/01/22 职场文书
教师工作表现自我评价
2015/03/05 职场文书
施工员岗位职责范本
2015/04/11 职场文书
反邪教观后感
2015/06/11 职场文书