avalon js实现仿微博拖动图片排序


Posted in Javascript onAugust 14, 2015

下文针对仿微博图片随意拖动,调整图片的顺序,讲解的很详细,文章肯定还有欠缺的地方,欢迎提出批评改正。废话不多说了,看具体内容吧。

点击此处进入源码下载

什么是拖动图片排序?

就像微博这种,上传后允许用户通过拖动图片,调整几张图片的顺序。

avalon js实现仿微博拖动图片排序

可以看到微博在这里把每张图片固定了尺寸,稍微严谨点的话,就需要像上一篇文章那样,外面是响应式的等高等宽的若干div容器,里面则是等比例缩放的响应式图片。

下面说下要求。

1.当然首先图片要可以拖动。

2.图片移出其原本的位置,拖动到目标位置并且未松开鼠标完成拖动前,需要在目标位置设置占位符,让用户预览拖动完成后的效果。

3.响应式。尺寸改变后,仍然可以完成上面要求。

4.尽可能兼容更多的浏览器。实际上,写上一篇文章就是为这篇做铺垫的,所以这里也是兼容到ie7.

最终效果

chrome

avalon js实现仿微博拖动图片排序

ie8

avalon js实现仿微博拖动图片排序

ie7

avalon js实现仿微博拖动图片排序

首先是拖动。

这里用的代理,即在原本的布局中多了个div,实际拖动的对象就是这个div.具体的,

<div id='wrap' ms-controller='drag_sort' class='ms-controller'>
 <ul ms-mousemove='drag_move($event)'>
 <li ms-repeat='photo_list'>
 <div ms-mousedown='start_drag($event,$index,el)'>
  <div class="dummy"></div>
  <p ms-attr-id='wrap_img{{$index}}'><img ms-attr-src="el.src"><i></i></p>
 </div>
 </li>
 </ul>
 <div id='drag_proxy'></div>
 </div>

对每个单元格绑定mousedown,触发start_drag时,把单元格里的img放到代理<div id='drag_proxy'></div>里面,同时获取图片的大小,记下当前鼠标点击的位置,并以点击位置为代理div矩形(图片)的中心点,显示代理,隐藏点击的图片。

avalon js实现仿微博拖动图片排序

start_drag:function(e,i,el){
 var img=$('wrap_img'+i).firstChild,target_img_width=img.clientWidth,target_img_height=img.clientHeight;
 drag_sort.cell_size=$('wrap_img0').clientWidth;
 var xx=e.clientX-target_img_width/2,yy=e.clientY-target_img_height/2,offset=avalon($(drag_sort.container)).offset(),target=e.target.parentNode.parentNode.parentNode; 
 $('drag_proxy').style.top=yy+avalon(window).scrollTop()-offset.top+'px';
 $('drag_proxy').style.left=xx-offset.left+'px';
 $('drag_proxy').style.width=target_img_width+'px';
 $('drag_proxy').style.height=target_img_height+'px';
 if(target&&target.nodeName=='LI'){
  ori_src=el;
  // $('drag_proxy').innerHTML=target.querySelector('p').innerHTML;
  $('drag_proxy').innerHTML=$('wrap_img'+i).innerHTML;
  $('drag_proxy').style.display='block';
  drag_sort.target_index=i;
  drag_flag=true;
 }
 if(isIE)
  target.setCapture();
 avalon.bind(document,'mouseup',function(){
  up(target);
 });
 e.stopPropagation();
 e.preventDefault();
 }

注意几点:

1.drag_sort.cell_size记录当前单元格的尺寸,这里宽高比是1:1,因为布局是响应式,所以需要记录。后面可以看到这个怎么用。

2.事件的target需要判断是不是img标签触发的,因为有可能点击位置是单元格与图片间的空白区域。

3.ori_src用来保存当前单元格的图片,因为后面mousemove的时候会删除图片原本位置的单元格。

4.drag_sort.target_index记录当前单元格的index,后面会比较这个index和代理移动到的单元格的index.

5.drag_flag表示是否可以mousemove了。

6.对于ie,必须target.setCapture();,否则

avalon js实现仿微博拖动图片排序

可以看到拖动的时候会执行浏览器的默认行为。

7.event.preventDefault();也必须加上,否则也会出现浏览器的默认行为,比如firefox拖动图片时,会打开新标签页,显示图片。

然后是mousemove,这里绑定在ul标签上。像mousemove,mouseup事件通常都绑定在若干需要触发元素的公共父元素上,这样就减少了事件绑定的对象了。

具体的

drag_move:function(e){
 if(drag_flag){
  var xx=e.clientX,yy=e.clientY,offset=avalon($(drag_sort.container)).offset();
  var x=xx-offset.left,y=avalon(window).scrollTop()+yy-offset.top;
  var x_index=Math.floor(x/drag_sort.cell_size),y_index=Math.floor(y/drag_sort.cell_size),move_to=3*y_index+x_index;
  $('drag_proxy').style.top=y-drag_sort.cell_size/2+'px';
  $('drag_proxy').style.left=x-drag_sort.cell_size/2+'px';
  if(move_to!=drag_sort.target_index){
  drag_sort.photo_list.removeAt(drag_sort.target_index);
  drag_sort.photo_list.splice(move_to,0,{src:'1.jpg'});
  drag_sort.target_index=move_to;
  }
 }
 e.stopPropagation();
 }

几点说明

1.drag_flag保证必须先触发mousedown后,才可以触发mousemove.

2.drag_sort.container是整个布局的根元素,这里是<div id='wrap'></div>.

#wrap{
 position: relative;
 max-width: 620px;
 font-size: 0;
 }
 #drag_proxy{
 position: absolute;
 border:1px solid #009be3;
 z-index: 100;
 display: none;
 }

后面计算的时候要把根元素的left,top减掉。

3.计算时avalon(window).scrollTop()浏览器的竖直滚动条也要考虑。

4.每个单元格的尺寸始终是一样的,所以直接光标移动到的位置除以行数,列数,取整,得到目标单元格的index.

5.move_to!=drag_sort.target_index当前光标移到的单元格不是图片原本所在的单元格,删除图片原本位置的单元格,在目标单元格插入占位的单元格,这时拖动的图片还没放进目标单元格,最后更新初始单元格的index.

最后是mouseup

function up(target){
 if(isIE)
 target.releaseCapture();
 var target_index=drag_sort.target_index;
 if(ori_src&&target_index!=-1){
 drag_sort.photo_list.splice(target_index,1);
 drag_sort.photo_list.splice(target_index,0,ori_src);
 }
 drag_holder=null;
 drag_flag=false;
 drag_sort.target_index=-1;
 $('drag_proxy').style.display='none';
 avalon.unbind(document,'mouseup');
 }

判断ori_src&&target_index!=-1目的在于排除在非绑定对象上mouseup这种无效操作。因为是在document上绑定mouseup,就要排除类似于随便在空白处点击这种情况。这时不能对单元格删除,插入。

然后是把各变量设为初始值。

图片效果:

avalon js实现仿微博拖动图片排序

HTML代码:

<div id='post_img' ms-controller='post_img'>
<ul id='post_img_inner' ms-mousemove='onmousemove'>
<li ms-repeat-el="post_img_list" class='inline-block' ms-mousedown='onmousedown($event,$index,el)' ms-attr-id='post_img_item{{$index}}'>
<img ms-src='el' class='uploaded_img'></li>
</ul>
</div>

JS代码:

var drag_holder=null,index=-1,ori_src=null,drag_flag=false;//拖动的代理,原图片,原图片的src
var post_img = avalon.define('post_img', function(vm) {
vm.post_img_list=[];//保存所有图片的src
vm.onmousedown=function(e,i,el){
$('drag_proxy').style.display='block';
var target=e.target.parentNode;
var xx = e.clientX;
var yy = e.clientY;
$('drag_proxy').style.top=yy+'px';
$('drag_proxy').style.left=xx+'px';
if(target&&target.nodeName=='LI'){
ori_src=el;
index=target.getAttribute('id').substring(13);
$('drag_proxy').innerHTML=target.innerHTML;
post_img.post_img_list.splice(i, 1, 'about:blank');
}
drag_flag=true;
};
vm.onmousemove=function(e){
if(drag_flag){//如果点下了图片
var xx = e.clientX;
var yy = e.clientY;
$('drag_proxy').style.top=yy+'px';
$('drag_proxy').style.left=xx+'px';
var x=xx-avalon($('post_img')).offset().left;
var y=yy-avalon($('post_img')).offset().top;
//例子没有考虑滚动条的情况
var x_index=Math.floor(x/100);//图片尺寸100*100
var y_index=Math.floor(y/100);
post_img.post_img_list.splice(index, 1);//删除当前图片的li
var target_index=3*y_index+x_index;//目标图片的位置(3*3)
if(post_img.post_img_list.indexOf('about:blank')!=target_index)
//如果图片数组中没有src=about:blank这个占位置的li
post_img.post_img_list.splice(target_index, 0, 'about:blank');
//添加src=about:blank
index=target_index;
//会触发很多次move,所以触发一次就改动一次
}
};
});
document.onmouseup=function(e){
drag_holder=null;
if(ori_src){
post_img.post_img_list.splice(index, 1);
//删除src=about:blank
post_img.post_img_list.splice(index, 0,ori_src);
//添加原图片
}
$('drag_proxy').style.display='none';
$('drag_proxy').innerHTML='';
drag_flag=false;
};

以上代码实现了avalon js仿微博拖动图片排序的功能,本文写的不好还请见谅。

Javascript 相关文章推荐
jquery中change()用法实例分析
Feb 06 Javascript
js日期范围初始化得到前一个月日期的方法
May 05 Javascript
怎么通过onclick事件获取js函数返回值(代码少)
Jul 28 Javascript
javascript记住用户名和登录密码(两种方式)
Aug 04 Javascript
JavaScript编程的单例设计模讲解
Nov 10 Javascript
基于javascript数组实现图片轮播
May 02 Javascript
jQuery 实现ajax传入参数含有特殊字符的方法总结
Oct 17 Javascript
JavaScript登录验证码的实现
Oct 27 Javascript
解析微信JS-SDK配置授权,实现分享接口
Dec 09 Javascript
javascript 初学教程及五子棋小程序的简单实现
Jul 04 Javascript
vue中使用微信公众号js-sdk踩坑记录
Mar 29 Javascript
微信小程序实现身份证取景框拍摄
Sep 09 Javascript
javascript实现显示和隐藏div方法汇总
Aug 14 #Javascript
freemarker判断对象是否为空的方法
Aug 13 #Javascript
数据分析软件之FineReport教程:[5]参数界面JS(全)
Aug 13 #Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
Aug 13 #Javascript
再JavaScript的jQuery库中编写动画效果的指南
Aug 13 #Javascript
js实现仿网易点击弹出提示同时背景变暗效果
Aug 13 #Javascript
JavaScript生成SQL查询表单的方法
Aug 13 #Javascript
You might like
一个可以删除字符串中HTML标记的PHP函数
2006/10/09 PHP
php对大文件进行读取操作的实现代码
2013/01/23 PHP
Apache连接PHP后无法启动问题解决思路
2015/06/18 PHP
php计算多维数组中所有值总和的方法
2015/06/24 PHP
php mysql 封装类实例代码
2016/09/18 PHP
实现PHP搜索加分页
2016/10/12 PHP
PHP使用标准库spl实现的观察者模式示例
2018/08/04 PHP
JavaScript中判断两个字符串是否相等的方法
2015/07/07 Javascript
jQuery实现带有上下控制按钮的简单多行滚屏效果代码
2015/09/04 Javascript
javascript实现网页端解压并查看zip文件
2015/12/15 Javascript
浅析BootStrap Treeview的简单使用
2016/10/12 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
2016/12/19 Javascript
JQuery和HTML5 Canvas实现弹幕效果
2017/01/04 Javascript
微信小程序 基础组件与导航组件详细介绍
2017/02/21 Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
2017/08/23 Javascript
浅谈Node.js 中间件模式
2018/06/12 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
2019/05/10 Javascript
es6函数之rest参数用法实例分析
2020/04/18 Javascript
JS中循环遍历数组的四种方式总结
2021/01/23 Javascript
代码块高亮可复制显示js插件highlight.js+clipboard.js整合
2021/02/15 Javascript
Python函数中*args和**kwargs来传递变长参数的用法
2016/01/26 Python
利用python写个下载teahour音频的小脚本
2017/05/08 Python
Python 实现「食行生鲜」签到领积分功能
2018/09/26 Python
解决python2 绘图title,xlabel,ylabel出现中文乱码的问题
2019/01/29 Python
tensorflow如何批量读取图片
2019/08/29 Python
python矩阵运算,转置,逆运算,共轭矩阵实例
2020/05/11 Python
Python面向对象多态实现原理及代码实例
2020/09/16 Python
澳大利亚著名的纺织品品牌:Canningvale
2020/05/05 全球购物
销售自荐信
2013/10/22 职场文书
采购部主管岗位职责
2014/01/01 职场文书
给分销商的致歉信
2014/01/14 职场文书
市场营销个人求职信范文
2014/02/02 职场文书
《蒲公英》教学反思
2014/02/28 职场文书
销售经理竞聘书
2014/03/31 职场文书
民间借贷协议书范本
2014/10/01 职场文书
python DataFrame中stack()方法、unstack()方法和pivot()方法浅析
2022/04/06 Python