Maison  >  Article  >  interface Web  >  avalon js implémente le tri par glisser-déposer de plusieurs images imitant Google Plus avec les compétences download_javascript du code source

avalon js implémente le tri par glisser-déposer de plusieurs images imitant Google Plus avec les compétences download_javascript du code source

WBOY
WBOYoriginal
2016-05-16 15:38:091488parcourir

Téléchargement du code source : http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar

L'effet est illustré ci-dessous :

google plus


Effet réactif au glisser :

Exigences

1. Disposition alignée des deux côtés, c'est-à-dire que l'espacement entre les images est le même, mais la distance entre les images gauche et droite et la bordure n'est pas nécessairement égale à l'espacement entre les images, compatible avec ie7, 8, Firefox, Chrome.
2. La taille du navigateur change. Lorsqu'elle dépasse une certaine taille, chaque ligne ajoutera ou réduira automatiquement les images et ajustera automatiquement l'espacement entre les images pour répondre à la disposition d'alignement des deux côtés. chaque image est fixe (ici 200*200px) et si elle est plus petite qu'à une certaine taille, le nombre d'images dans chaque ligne est fixe (le nombre minimum de colonnes ici est de 3), et les images sont toujours étirées ou mis à l'échelle dans des proportions égales.
3. Vous pouvez toujours faire glisser et trier sous différentes tailles de navigateur.
4. Pour les images, faites glisser les images dans l'agent pour toujours conserver des proportions égales et être centrées horizontalement et verticalement.
5. Lorsqu'elles sont glissées vers la position correspondante, les images à gauche et à droite de la position seront décalées dans une certaine mesure. S'il se trouve à l'extrême gauche ou à droite, seule la première ou la dernière image de la ligne est décalée.
6. Prend en charge le glisser et le tri de plusieurs images.

Réussite

Mise en page et 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

Cela doit être compatible avec les versions inférieures des navigateurs, donc la mise en page de la liste utilise un bloc en ligne et la mise en page est alignée des deux côtés

.

-Version basse : bloc en ligne `text-align:justify`

-Moderne : bloc en ligne `flex-box`

Pour plus de détails, veuillez vous référer à cette simulation de l'espace entre flexbox justification-content

Le `align-content:space-around` de flex-box n'est pas utilisé ici car il n'est pas compatible avec les versions inférieures des navigateurs via `text-align:justify`.

`text-align:justify` ne peut pas permettre au texte le plus à gauche et le plus à droite d'ajuster automatiquement la distance par rapport au bord de la boîte. Même si vous ajoutez du padidng dans la zone extérieure, comme :

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

Il semble que la distance entre les cases les plus à gauche et les plus à droite et la limite de la case soit la même que la distance entre li, qui est de 2 %. En fait, le remplissage défini par la boîte extérieure ne changera jamais et la marge entre li est la valeur minimale de l'espacement entre eux. Si l'espacement entre tous les li est de 1 %, alors il y a encore de l'espace supplémentaire sur une ligne, et ces li diviseront l'espace de manière égale, et l'espacement entre eux sera supérieur à 1 %.
Mise en œuvre spécifique

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

Vous devez ajouter ici « max-width » et « max-height » Vous pourrez voir plus tard que les cellules sont remplies de pourcentages et que la taille maximale doit être limitée à l'extérieur.

Image responsive, centrée horizontalement et verticalement

Pour plus de détails, veuillez vous référer à ce centrage vertical et horizontal réactif aux images CSS

Sélectionner une image

Dans Google Plus, maintenez la touche Ctrl enfoncée et cliquez sur l'image pour effectuer plusieurs sélections. Ici, cliquez sur la "case" (`7551d6eed0d1abb8ee13940238e494625db79b134e9f6b82c0b36e0489ee08ed` ici).
Après avoir cliqué, l'index de l'image actuelle est transmis au tableau qui enregistre l'index de l'image sélectionnée (selected_index ici). Si l'index n'existe pas, ajoutez-le ; s'il existe déjà, supprimez-le. La "boîte" ajuste son style selon que l'index existe ou non dans le tableau.

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

souris enfoncée

Un calque de masque est utilisé ici, et l'événement mousedown y est lié.

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

Cliquez sur la souris et le masque de l'image sélectionnée apparaîtra. Voici pour ajouter `.photo_maskon`

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

déplacement de la souris

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

Quelques notes
- Détermination de la position actuelle traînée

La ligne verticale de chaque cellule de l'image divise la cellule en deux côtés dans le sens horizontal. Chaque ligne verticale divise une ligne en 5 parties. Lors du jugement, regardez à quelle partie des 5 parties se trouve le « e.clientX » actuel de la souris.

- Le tri est utilisé ici lors du jugement. Plus précisément, enregistrez la coordonnée x de chaque ligne verticale et la coordonnée x de la position actuelle de la souris dans un tableau (`sort_array` ici), triez-les, puis utilisez `indexOf` pour voir la position de la coordonnée x de la souris actuelle. position dans le tableau. Vous pouvez obtenir la position actuelle de la cible de déplacement.

S'il n'y a pas besoin de trier, le code ressemblera à ceci

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;

- Supprimez plus tard la coordonnée x de la position actuelle de la souris, laissant la position vacante pour la coordonnée x du prochain événement mousemove.
- Concernant le décalage des images à gauche et à droite de la position cible actuellement déplacée, il ne s'agit que d'ajouter la classe correspondante aux images à gauche et à droite de la position cible.

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

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn