Home Web Front-end JS Tutorial avalon js implements drag sorting of multiple images imitating google plus with source code download_javascript skills

avalon js implements drag sorting of multiple images imitating google plus with source code download_javascript skills

May 16, 2016 pm 03:38 PM

Source code download: http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar

The effect is shown below:

google plus


Drag responsive effect:

Requirements

1. Aligned layout on both sides, that is, the spacing between the pictures is the same, but the distance between the left and right pictures and the border is not necessarily equal to the spacing between the pictures, compatible with ie7, 8, firefox, chrome.
2. The size of the browser changes. When it is larger than a certain size, each row will automatically add or reduce pictures, and automatically adjust the spacing between pictures to meet the alignment layout on both sides. At this time, the size of each picture is fixed (here is 200*200px); and if it is smaller than At a certain size, the number of pictures in each row is fixed (the minimum number of columns here is 3), and the pictures are always stretched or scaled in equal proportions.
3. You can still drag and sort under different browser sizes.
4. For pictures, drag the pictures in the agent to always maintain equal proportions and be centered horizontally and vertically.
5. When dragged to the corresponding position, the pictures to the left and right of the position will be offset to a certain extent. If it is on the far left or right, only the first or last picture of the row is offset.
6. Supports dragging and sorting of multiple pictures.

Achievement

Layout and 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
Copy after login

This needs to be compatible with lower version browsers, so the list li layout uses inline-block. And the layout is aligned on both sides

-Low version: inline-block `text-align:justify`

-Modern: inline-block `flex-box`

For details, please refer to this simulation of flexbox justify-content’s space-between

The `align-content:space-around` of flex-box is not used here because it is not compatible with lower version browsers through `text-align:justify`.

`text-align:justify` cannot allow the leftmost and rightmost text to automatically adjust the distance from the box edge. Even if you add padidng in the outer box, such as:

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

It seems that the distance between the leftmost and rightmost boxes and the box boundary is the same as the distance between li, which is 2%. In fact, the padding set by the outer box will never change, and the margin between li is the minimum value of the spacing between them. If the spacing between all li's is 1%, then there is still extra space on a line, and these li's will divide the space evenly, and the spacing between them will be greater than 1%.
Specific implementation

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%;
 }
}
Copy after login

You need to add `max-width` and `max-height` here. You can see later that the cells are filled with percentages, and the maximum size needs to be limited outside.

Responsive image, centered horizontally and vertically

For details, please refer to this css image responsive vertical and horizontal centering

Select picture

In Google Plus, hold down ctrl and click on the picture to complete multiple selections. Here, click on the "box" (`` here).
After clicking, the index of the current picture is passed to the array that saves the index of the selected picture (selected_index here). If the index does not exist, add it; if it already exists, delete it. The "box" adjusts its style based on whether the index exists in the array.

<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);
 }
});
Copy after login

mousedown

A mask layer is used here, and the mousedown event is bound to it.

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

Copy after login

Click the mouse and the mask of the selected picture will appear. Here is to add `.photo_maskon`

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

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

A few notes
- Determination of the current dragged position

The vertical line of each cell in the picture divides the cell into two sides in the horizontal direction. Each vertical line divides a line into 5 parts. When judging, look at which part of the 5 parts the current `e.clientX` of the mouse is.

- Sorting is used here when judging. Specifically, save the x coordinate of each vertical line and the x coordinate of the current mouse position to an array (`sort_array` here), sort them, and then use `indexOf` to see the position of the x coordinate of the current mouse position in the array. You can get the current drag target position.

If there is no need to sort, the code will look like this

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;
Copy after login

- Later delete the x coordinate of the current mouse position, leaving the position vacant for the x coordinate of the next mousemove event.
- Regarding the offset of the pictures to the left and right of the currently dragged target position, it is nothing more than adding the corresponding class to the pictures to the left and right of the target position.

.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>
Copy after login

这里需要注意,当代理拖动到最左边或最右边时,由于布局是`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>
Copy after login

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

这里主要就是对图片列表的重排。
- 目标位置在选中图片之前

 

先把原始图片保存在`temp`,然后把从目标位置图片到原始图片前一位置的图片,依次后移一个位置,最后把`temp`放到目标位置。
- 目标位置在选中图片之后

 

和上面差不多,只不过这里是把从目标位置图片到原始图片后一位置的图片,依次前移一个位置。

注意

不能像`data[j]=data[j+1]`这样赋值,因为avalon不支持单个转换,如果想更新,需要将整个子VM重新赋以一个新的对象。也就是定义一个arr,然后从头开始向里面添加model,最后`photo_sort.photo_list.clear()`删除所有图片,`photo_sort.photo_list=arr`重新赋值,更新视图。

后记

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

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Is JavaScript hard to learn? Is JavaScript hard to learn? Apr 03, 2025 am 12:20 AM

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

See all articles