Heim  >  Artikel  >  Web-Frontend  >  Avalon js implementiert die Drag-Sortierung mehrerer Bilder imitiert Google Plus mit Fähigkeiten zum Herunterladen von Quellcode-Javascript

Avalon js implementiert die Drag-Sortierung mehrerer Bilder imitiert Google Plus mit Fähigkeiten zum Herunterladen von Quellcode-Javascript

WBOY
WBOYOriginal
2016-05-16 15:38:091488Durchsuche

Quellcode-Download: http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar

Der Effekt ist unten dargestellt:

Google Plus


Drag-Response-Effekt:

Anforderungen

1. Auf beiden Seiten ausgerichtetes Layout, d. h. der Abstand zwischen den Bildern ist gleich, aber der Abstand zwischen den linken und rechten Bildern und dem Rand entspricht nicht unbedingt dem Abstand zwischen den Bildern, kompatibel mit ie7, 8, Firefox, Chrom.
2. Wenn die Größe des Browsers größer als eine bestimmte Größe ist, werden in jeder Zeile automatisch Bilder hinzugefügt oder verkleinert und der Abstand zwischen den Bildern automatisch angepasst, um dem Ausrichtungslayout auf beiden Seiten zu entsprechen Jedes Bild ist fest (hier 200 * 200 Pixel). Wenn es kleiner ist als Bei einer bestimmten Größe ist die Anzahl der Bilder in jeder Zeile festgelegt (die Mindestanzahl der Spalten beträgt hier 3) und die Bilder werden immer gestreckt oder in gleichen Proportionen skaliert.
3. Sie können weiterhin verschiedene Browsergrößen ziehen und sortieren.
4. Ziehen Sie bei Bildern die Bilder im Agenten, um immer gleiche Proportionen beizubehalten und horizontal und vertikal zentriert zu sein.
5. Beim Ziehen an die entsprechende Position werden die Bilder links und rechts von der Position in gewissem Maße versetzt. Liegt es ganz links oder rechts, wird nur das erste bzw. letzte Bild der Reihe versetzt.
6. Unterstützt das Ziehen und Sortieren mehrerer Bilder.

Leistung

Layout und 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

Dies muss mit Browsern niedrigerer Versionen kompatibel sein, daher verwendet das Listen-Li-Layout einen Inline-Block und das Layout ist auf beiden Seiten ausgerichtet

-Niedrige Version: Inline-Block `text-align:justify`

-Modern: Inline-Block „Flex-Box“

Einzelheiten finden Sie in dieser Simulation des Leerzeichens von Flexbox Justify-Content

Der „align-content:space-around“ von Flex-Box wird hier nicht verwendet, da er über „text-align:justify“ nicht mit Browsern niedrigerer Versionen kompatibel ist.

`text-align:justify` kann nicht zulassen, dass der Text ganz links und ganz rechts den Abstand vom Rand des Felds automatisch anpasst. Auch wenn Sie padidng im äußeren Feld hinzufügen, z. B.:

li{
 margin:0 1%;
 ...
}
#wrap{
 padding:0 1%;
}

Es scheint, dass der Abstand zwischen den Kästchen ganz links und ganz rechts und der Kästchengrenze mit dem Abstand zwischen li identisch ist, der 2 % beträgt. Tatsächlich ändert sich die durch das äußere Feld festgelegte Polsterung nie, und der Abstand zwischen li ist der Mindestwert des Abstands zwischen ihnen. Wenn der Abstand zwischen allen Lis 1 % beträgt, gibt es immer noch zusätzlichen Platz auf einer Linie, und diese Lis teilen den Raum gleichmäßig auf und der Abstand zwischen ihnen ist größer als 1 %.
Spezifische Implementierung

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%;
 }
}

Hier müssen Sie „max-width“ und „max-height“ hinzufügen. Später sehen Sie, dass die Zellen mit Prozentsätzen gefüllt sind und die maximale Größe außen begrenzt werden muss.

Responsives Bild, horizontal und vertikal zentriert

Weitere Informationen finden Sie in dieser auf CSS-Bilder reagierenden vertikalen und horizontalen Zentrierung

Bild auswählen

Halten Sie in Google Plus die Strg-Taste gedrückt und klicken Sie auf das Bild, um die Mehrfachauswahl abzuschließen. Klicken Sie hier auf das „Feld“ (`7551d6eed0d1abb8ee13940238e494625db79b134e9f6b82c0b36e0489ee08ed`).
Nach dem Klicken wird der Index des aktuellen Bildes an das Array übergeben, das den Index des ausgewählten Bildes speichert (hier selected_index). Wenn der Index nicht vorhanden ist, fügen Sie ihn hinzu. Wenn er bereits vorhanden ist, löschen Sie ihn. Das „Feld“ passt seinen Stil basierend darauf an, ob der Index im Array vorhanden ist.

<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

Hier wird eine Maskenebene verwendet, an die das Mousedown-Ereignis gebunden ist.

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

Klicken Sie mit der Maus und die Maske des ausgewählten Bildes wird angezeigt. Hier können Sie „.photo_maskon“ hinzufügen.

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

Mausbewegung

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

Ein paar Anmerkungen
- Ermittlung der aktuellen Schleppposition

Die vertikale Linie jeder Zelle im Bild teilt die Zelle in horizontaler Richtung in zwei Seiten. Jede vertikale Linie teilt eine Linie in 5 Teile. Achten Sie bei der Beurteilung darauf, welcher Teil der 5 Teile der aktuelle „e.clientX“ der Maus ist.

- Bei der Beurteilung kommt hier die Sortierung zum Einsatz. Speichern Sie insbesondere die x-Koordinate jeder vertikalen Linie und die x-Koordinate der aktuellen Mausposition in einem Array (hier „sort_array“), sortieren Sie sie und verwenden Sie dann „indexOf“, um die Position der x-Koordinate der aktuellen Maus anzuzeigen Position im Array Sie können die aktuelle Drag-Zielposition abrufen.

Wenn keine Sortierung erforderlich ist, sieht der Code so aus

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;

- Löschen Sie später die X-Koordinate der aktuellen Mausposition und lassen Sie die Position für die X-Koordinate des nächsten Mausbewegungsereignisses frei.
- Bezüglich des Versatzes der Bilder links und rechts von der aktuell gezogenen Zielposition ist es nichts anderes, als den Bildern links und rechts von der Zielposition die entsprechende Klasse hinzuzufügen.

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

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn