Muat turun kod sumber: http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar
Kesannya ditunjukkan di bawah:
google plus
Seret kesan responsif:
Keperluan
1. Susun atur sejajar pada kedua-dua belah, iaitu jarak antara gambar adalah sama, tetapi jarak antara gambar kiri dan kanan dan sempadan tidak semestinya sama dengan jarak antara gambar, serasi dengan ie7, 8, firefox, krom.
2. Saiz pelayar berubah Apabila ia lebih besar daripada saiz tertentu, setiap baris secara automatik akan menambah atau mengurangkan gambar, dan secara automatik melaraskan jarak antara gambar untuk memenuhi susun atur penjajaran pada kedua-dua belah setiap gambar ditetapkan (di sini ialah 200*200px dan jika ia lebih kecil daripada Pada saiz tertentu, bilangan gambar dalam setiap baris adalah tetap (bilangan minimum lajur di sini ialah 3), dan gambar sentiasa diregangkan atau berskala dalam perkadaran yang sama.
3. Anda masih boleh menyeret dan mengisih di bawah saiz pelayar yang berbeza.
4. Untuk gambar, seret gambar dalam ejen untuk sentiasa mengekalkan perkadaran yang sama dan dipusatkan secara mendatar dan menegak.
5. Apabila diseret ke kedudukan yang sepadan, gambar ke kiri dan kanan kedudukan akan diimbangi ke tahap tertentu. Jika ia berada di hujung kiri atau kanan, hanya gambar pertama atau terakhir baris diimbangi.
6. Menyokong menyeret dan menyusun berbilang gambar.
Pencapaian
Reka letak dan css
<div id='wrap'> <ul class='justify'> <li> <a href="javascript:;" class="no_selected"></a> <div class='photo_mask'></div> <div> <div class="dummy"></div> <p><img><i></i></p> </div> </li> <li class='justify_fix'></li> </ul> </div> inline-block+flex-box+text-align:justify
Ini perlu serasi dengan penyemak imbas versi yang lebih rendah, jadi susun atur senarai li menggunakan blok sebaris Dan reka letak dijajarkan pada kedua-dua belah pihak
-Versi rendah: inline-block `text-align:justify`
-Moden: inline-block `flex-box`
Untuk butiran, sila rujuk simulasi ruang antara kandungan flexbox justify-content
`align-content:space-around` flex-box tidak digunakan di sini kerana ia tidak serasi dengan pelayar versi rendah melalui `text-align:justify`.
`text-align:justify` tidak boleh membenarkan teks paling kiri dan paling kanan melaraskan jarak secara automatik dari tepi kotak. Walaupun anda menambah padidng di dalam kotak luar, seperti:
li{ margin:0 1%; ... } #wrap{ padding:0 1%; }
Nampaknya jarak antara kotak paling kiri dan paling kanan dengan sempadan kotak adalah sama dengan jarak antara li, iaitu 2%. Malah, padding yang ditetapkan oleh kotak luar tidak akan berubah, dan margin antara li ialah nilai minimum jarak antara mereka. Jika jarak antara semua li ialah 1%, maka masih terdapat ruang tambahan pada satu baris, dan li ini akan membahagikan ruang sama rata dan jarak antaranya akan lebih besar daripada 1%.
Pelaksanaan khusus
li{ list-style-type: none; display:inline-block; *display: inline; zoom:1; max-width: 200px; max-height: 200px; width: 28%; border:1px solid red; position: relative; overflow: hidden; margin:10px 2%; } li[class='justify_fix']{ border:none; } .justify { display: flex; align-items: flex-start; flex-flow: row wrap; justify-content: space-between; text-align: justify; text-justify: inter-ideograph; *zoom: 1; -moz-text-align-last: justify; -webkit-text-align-last: justify; text-align-last: justify; } @media (-webkit-min-device-pixel-ratio:0) { .justify:after { content: ""; display: inline-block; width: 100%; } }
Anda perlu menambah `max-width` dan `max-height` di sini Anda boleh melihat kemudian bahawa sel dipenuhi dengan peratusan dan saiz maksimum perlu dihadkan di luar.
Imej responsif, berpusat secara mendatar dan menegak
Untuk butiran, sila rujuk imej css responsif menegak dan mendatar ini berpusat
Pilih gambar
Dalam Google Plus, tahan ctrl dan klik pada gambar untuk melengkapkan berbilang pilihan Di sini, klik pada "kotak" (`` di sini.
Selepas mengklik, indeks gambar semasa dihantar ke tatasusunan yang menyimpan indeks gambar yang dipilih (selected_index di sini). Jika indeks tidak wujud, tambahkannya jika sudah ada, padamkannya. "Kotak" melaraskan gayanya berdasarkan sama ada indeks wujud dalam tatasusunan.
<div id='wrap' ms-controller='photo_sort'> <ul class='justify'> <li ms-repeat='photo_list'> <a href="javascript:;" class="no_selected" ms-class-selected_icon='selected_index.indexOf($index)>-1' ms-click='select($index)'></a> ... </li> <li class='justify_fix'></li> </ul> </div> var photo_sort=avalon.define({ selected_index:[],//选中图片的index列表, ... select:function(i){ var selected_index=photo_sort.selected_index; if(selected_index.indexOf(i)==-1)//选中图片的index列表不存在,添加 photo_sort.selected_index.ensure(i); else photo_sort.selected_index.remove(i); } });
turun tetikus
Lapisan topeng digunakan di sini dan acara turun tetikus terikat padanya.
<a href="javascript:;" class="no_selected" ms-class-selected_icon='selected_index.indexOf($index)>-1' ms-click='select($index)'></a> <div class='photo_mask' ms-mousedown='start_drag($event,$index)'></div> var photo_sort=avalon.define({ $id:'photo_sort', photo_list:[],//图片列表 selected_index:[],//选中图片的index列表 drag_flag:false, sort_array:[],//范围列表, cell_size:0,//每个单元格尺寸,这里宽高比为1 target_index:-1,//最终目标位置的index col_num:0,//列数 x_index:-1,//当前拖动位置的x方向index ... }); start_drag:function(e,index){ if(photo_sort.selected_index.size()){//有选中的图片 photo_sort.target_index=index;//避免用户没有拖动图片,但点击了图片,设置默认目标即当前点击图片 photo_sort.cell_size=this.clientWidth; var xx=e.clientX-photo_sort.cell_size/2,yy=e.clientY-photo_sort.cell_size/2;//点下图片,设置代理位置以点击点为中心 $('drag_proxy').style.top=yy+avalon(window).scrollTop()+'px'; $('drag_proxy').style.left=xx+'px'; $('drag_proxy').style.width=photo_sort.cell_size+'px'; $('drag_proxy').style.height=photo_sort.cell_size+'px'; drag_proxy.select_num=photo_sort.selected_index.length;//设置代理中选择图片的数量 if(drag_proxy.select_num>0){ var drag_img=photo_sort.photo_list[photo_sort.selected_index[drag_proxy.select_num-1]]; drag_proxy.src=drag_img.src;//将选中的图片中最后一张作为代理对象的"封面" photo_sort.drag_flag=true; $('drag_proxy').style.display='block'; } //cell_gap:图片间间距,first_gap:第一张图片和外部div间间距 var wrap_width=avalon($('wrap')).width(),wrap_offset=$('wrap').offsetLeft,first_left=$('wrap_photo0').offsetLeft, second_left=$('wrap_photo1').offsetLeft,first_gap=first_left-wrap_offset,cell_gap=second_left-first_left; photo_sort.col_num=Math.round((wrap_width-2*first_gap+(cell_gap-photo_sort.cell_size))/cell_gap); for(var i=0;i<photo_sort.col_num;i++)//把一行图片里的每张图片中心坐标x方向的值作为分割点,添加到范围列表 photo_sort.sort_array.push(first_gap+cell_gap*i+photo_sort.cell_size/2); var target=this.parentNode; avalon.bind(document,'mouseup',function(e){ onMouseUp(target); }); if(isIE) target.setCapture();//让ie下拖动顺滑 e.stopPropagation(); e.preventDefault(); } }
Klik tetikus dan topeng gambar yang dipilih akan muncul Di sini adalah untuk menambah `.photo_maskon`
<div class='photo_mask' ms-class-photo_maskon='drag_flag&&selected_index.indexOf($index)>-1' ms-mousedown='start_drag($event,$index)'></div>
alih tetikus
drag_move:function(e){ if(photo_sort.drag_flag){ var xx=e.clientX,yy=e.clientY,offset=avalon($('wrap')).offset(); var offsetX=xx-offset.left,offsetY=yy-offset.top; photo_sort.sort_array.push(offsetX);//把当前鼠标位置添加的范围列表 photo_sort.sort_array.sort(function(a,b){//对范围列表排序 return parseInt(a)-parseInt(b);//转为数值类型,否则会出现'1234'<'333' }); //从已排序的范围列表中找出当前鼠标位置的index,即目标位置水平方向的index var x_index=photo_sort.sort_array.indexOf(offsetX),y_index=Math.floor(offsetY/(photo_sort.cell_size+20)), size=photo_sort.photo_list.size(); photo_sort.x_index=x_index; photo_sort.target_index=photo_sort.col_num*y_index+x_index;//目标在所有图片中的index if(photo_sort.target_index>size)//目标位置越界 photo_sort.target_index=size; photo_sort.sort_array.remove(offsetX);//移除当前位置 $('drag_proxy').style.top=avalon(window).scrollTop()+yy-photo_sort.cell_size/2+'px'; $('drag_proxy').style.left=xx-photo_sort.cell_size/2+'px'; } e.stopPropagation(); }
Sedikit nota
- Penentuan kedudukan seret semasa
Garis menegak setiap sel dalam gambar membahagikan sel kepada dua sisi dalam arah mendatar. Setiap garisan menegak membahagikan garisan kepada 5 bahagian Apabila menilai, lihat bahagian mana daripada 5 bahagian `e.clientX` tetikus.
- Isih digunakan di sini apabila menilai. Khususnya, simpan koordinat x bagi setiap baris menegak dan koordinat x kedudukan tetikus semasa ke tatasusunan (`susun_susun` di sini), isikannya dan kemudian gunakan `indexOf` untuk melihat kedudukan koordinat x tetikus semasa kedudukan dalam tatasusunan Anda boleh mendapatkan kedudukan sasaran seret semasa.
Jika tidak perlu mengisih, kod akan kelihatan seperti ini
var target; if(x>50+50){ if(x>3*100+3*100+50+50){//最后一部分 target=4; }else{ target=(x-50-50)/(50+100+50); } }else target=0;
- Kemudian padamkan koordinat x kedudukan tetikus semasa, biarkan kedudukan kosong untuk koordinat x acara gerak tetikus seterusnya.
- Mengenai pengimbangan gambar ke kiri dan kanan kedudukan sasaran yang diseret pada masa ini, ia tidak lebih daripada menambah kelas yang sepadan pada gambar di kiri dan kanan kedudukan sasaran.
.prev{ right: 40px; } .next{ left: 40px; } <div id='wrap' ms-controller='photo_sort'> <ul class='justify' ms-mousemove='drag_move($event)'> <li ms-repeat='photo_list' ms-attr-id='wrap_photo{{$index}}' ms-class-prev='$index==target_index-1' ms-class-next='$index==target_index'> ... </li> <li class='justify_fix'></li> </ul> </div>
这里需要注意,当代理拖动到最左边或最右边时,由于布局是`inline-block`,此时目标位置所在行的上一行(如果有)的最后一个单元格或下一行(如果有)的第一个单元格也会发生偏移。
解决方法是设置变量`x_index`,表示单元格在x方向的index.在添加偏移class的时候,增加判定条件
<li ms-repeat='photo_list' ms-attr-id='wrap_photo{{$index}}' ms-class-prev='$index==target_index-1&&x_index>0' ms-class-next='$index==target_index&&x_index<col_num'> ... </li>
mouseup
function onMouseUp(target){ if(photo_sort.drag_flag){ for(var i=0,len=photo_sort.selected_index.size();i<len;i++){//遍历选中图片 var item_index=photo_sort.selected_index[i],data=photo_sort.photo_list, target_index=photo_sort.target_index,temp; if(item_index<target_index){//目标位置在选中图片之后 temp=data[item_index].src; for(var j=item_index;j<target_index;j++) data[j].src=data[j+1].src; data[target_index-1].src=temp; }else{//目标位置在选中图片之前 temp=data[item_index].src; for(var j=item_index;j>target_index;j--) data[j].src=data[j-1].src; data[target_index].src=temp; } } photo_sort.target_index=-1;//各种重置,初始化 photo_sort.sort_array=[]; photo_sort.col_num=0; photo_sort.x_index=-1; photo_sort.selected_index=[]; $('drag_proxy').style.display='none'; photo_sort.drag_flag=false; avalon.unbind(document,'mouseup'); if(isIE) target.releaseCapture(); } }
这里主要就是对图片列表的重排。
- 目标位置在选中图片之前
先把原始图片保存在`temp`,然后把从目标位置图片到原始图片前一位置的图片,依次后移一个位置,最后把`temp`放到目标位置。
- 目标位置在选中图片之后
和上面差不多,只不过这里是把从目标位置图片到原始图片后一位置的图片,依次前移一个位置。
注意
不能像`data[j]=data[j+1]`这样赋值,因为avalon不支持单个转换,如果想更新,需要将整个子VM重新赋以一个新的对象。也就是定义一个arr,然后从头开始向里面添加model,最后`photo_sort.photo_list.clear()`删除所有图片,`photo_sort.photo_list=arr`重新赋值,更新视图。
后记
事实上,google plus在细节上还做了
- 框选图片
- 如果有滚动条,且拖动位置快要超出当前界面,滚动条会自动上移或下移。
这两个本屌就不做了,原理也是很简单的。