首頁 web前端 js教程 avalon js實作仿google plus圖片多張拖曳排序附原始碼下載_javascript技巧

avalon js實作仿google plus圖片多張拖曳排序附原始碼下載_javascript技巧

May 16, 2016 pm 03:38 PM

原始碼下載:http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar

效果顯示如下:

google plus

 

 


拖曳 響應式效果:

 

要求

1. 兩邊對齊佈局,即圖片間距一致,但左右兩邊的圖片與邊界的間距不一定等於圖片間距,相容於ie7,8,firefox,chrome.
2. 瀏覽器尺寸變化,在大於一定尺寸時,每行自動增加或減少圖片,自動調整圖片間距,以滿足兩邊對齊佈局,這時每張圖片尺寸固定(這裡是200*200px);而小於當一定尺寸時,每行圖片數量固定(這裡最小列數是3),這時圖片總是等比例拉伸或縮放。
3. 瀏覽器不同尺寸下,仍可拖曳排序。
4. 圖片,拖曳代理程式裡的圖片始終保持等比例且水平垂直居中。
5. 拖曳到對應位置時,位置左右的圖片會發生一定偏移。如果在最左邊或最右邊,則只是該行的第一張圖片或最後一張圖片發生偏移。
6. 支援多張圖片拖曳排序。

實作

佈局及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
登入後複製

這裡要相容於低版瀏覽器,所以列表li版面用的是inline-block.而兩邊對齊版面配置

-低版:inline-block `text-align:justify`

-現代:inline-block `flex-box`

具體參考本屌的模擬flexbox justify-content的space-between

這裡沒有用flex-box的`align-content:space-around`是因為無法透過`text-align:justify`來相容低版瀏覽器。

`text-align:justify`無法讓最左邊,最右邊文字自動調整與box邊的間距。即使在外面box添加padidng,例如:

li{
 margin:0 1%;
 ...
}
#wrap{
 padding:0 1%;
}
登入後複製

看起來好像是最左邊,最右邊與box邊界的間距和li之間的間距一樣,都是2%了。實際上,外面box設定的padding是永遠不會改變的,而li之間的margin是它們之間間距的最小值。如果所有li之間的間距都是1%,這時,一行上仍然有多餘的空白,這些li會把空白均分了,這時它們之間的間距會大於1%.
具體的實現

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%;
 }
}
登入後複製

這裡要加上`max-width`,`max-height`.後面可以看到單元格裡面都是百分比,需要在外面限定最大尺寸。

圖片響應式 水平垂直居中

具體參見本屌的css圖片響應式 垂直水平居中

選取圖片

google plus是按住ctrl,點擊圖片,完成多選,這裡是點擊"方框"(這裡的``)。
點選後,把目前圖片的index傳給保存選取圖片index的陣列(這裡的selected_index)。如果該index不存在,則新增;已存在,則刪除。而"方框"此時根據數組中是否存在該index調整樣式。

<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);
 }
});
登入後複製

mousedown

這裡用了遮罩層,並在上面綁定mousedown事件。

<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();
 }
}

登入後複製

滑鼠點下,選取的圖片的遮罩出現,這裡是對其添加`.photo_maskon`

<div class='photo_mask' ms-class-photo_maskon='drag_flag&&selected_index.indexOf($index)>-1' 
ms-mousedown='start_drag($event,$index)'></div>
登入後複製

mousemove

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();
}
登入後複製

幾點說明
- 關於目前拖曳到的位置判定

 

圖中每個單元格的垂直線,在水平方向把單元格分為兩邊。每個垂直線把一行分成5部分,判斷的時候,看滑鼠目前的`e.clientX`在5個部分裡的哪一部分。

- 這裡在判斷的時候用了排序。具體的,把每個垂直線的x座標和目前滑鼠位置的x座標儲存到陣列(這裡的`sort_array`),排好序,然後`indexOf`看目前滑鼠位置的x座標在陣列中的位置,即可得到目前拖曳的目標位置。

如果不用排序的話,程式碼會像這樣

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;
登入後複製

- 後面刪除目前滑鼠位置的x座標,空出位置,留給下一次mousemove事件的x座標。
- 關於目前拖曳的目標位置左右的圖片發生一定偏移,無非就是對目標位置左右的圖片加上對應的class.

.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在细节上还做了
- 框选图片
- 如果有滚动条,且拖动位置快要超出当前界面,滚动条会自动上移或下移。
这两个本屌就不做了,原理也是很简单的。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何創建和發布自己的JavaScript庫? 如何創建和發布自己的JavaScript庫? Mar 18, 2025 pm 03:12 PM

文章討論了創建,發布和維護JavaScript庫,專注於計劃,開發,測試,文檔和促銷策略。

如何在瀏覽器中優化JavaScript代碼以進行性能? 如何在瀏覽器中優化JavaScript代碼以進行性能? Mar 18, 2025 pm 03:14 PM

本文討論了在瀏覽器中優化JavaScript性能的策略,重點是減少執行時間並最大程度地減少對頁面負載速度的影響。

前端熱敏紙小票打印遇到亂碼問題怎麼辦? 前端熱敏紙小票打印遇到亂碼問題怎麼辦? Apr 04, 2025 pm 02:42 PM

前端熱敏紙小票打印的常見問題與解決方案在前端開發中,小票打印是一個常見的需求。然而,很多開發者在實...

誰得到更多的Python或JavaScript? 誰得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

如何使用瀏覽器開發人員工具有效調試JavaScript代碼? 如何使用瀏覽器開發人員工具有效調試JavaScript代碼? Mar 18, 2025 pm 03:16 PM

本文討論了使用瀏覽器開發人員工具的有效JavaScript調試,專注於設置斷點,使用控制台和分析性能。

如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? 如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中將具有相同ID的數組元素合併到一個對像中?在處理數據時,我們常常會遇到需要將具有相同ID�...

如何使用源地圖調試縮小JavaScript代碼? 如何使用源地圖調試縮小JavaScript代碼? Mar 18, 2025 pm 03:17 PM

本文說明瞭如何使用源地圖通過將其映射回原始代碼來調試JAVASCRIPT。它討論了啟用源地圖,設置斷點以及使用Chrome DevTools和WebPack之類的工具。

神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

See all articles