使用jquery-sortable插件和acts_as_list rubygem实现页面拖动排序

Contents
  1. 需求
  2. 技术背景
    1. jquery-sortable交互工具
    2. acts_as_list rubygem
  3. 前端JS的实现
  4. 后端controller sort action的实现
  5. 定义路由表
  6. What is more
    1. jQuery UI Touch Punch

需求

我们经常有这样的需求:如下图所示,拖动不同item从页面上实现<li>的重新排序,并将其保存在数据库中。

需求

技术背景

jquery-sortable交互工具

jQuery UI 是一个建立在 jQuery JavaScript 库上的小部件和交互库,你可以使用它创建高度交互的 Web 应用程序。而 jquery-sortable 则可以实现使用鼠标调整列表中或者网格中元素的排序。它的 API 你可以点进link来了解。

acts_as_list rubygem

acts_as_list 是一个开源的rubygem,提供了方法实现列表中元素的sort和reorder,具体的API和source code点进link查看,在此不再赘述。

前端JS的实现

举例来说,我们要使用jquery-sortable为名为“article”的model实现页面交互排序,并使用ajax通过发送POST请求将JS获取的数据传到controller中,前端JS代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(function () {
if($('.Articles').length) {
$('ol.articles').sortable({
stop: function(event, ui) {
ui.item.data('endPos', ui.item.index()+1);
var data = {'end_position': ui.item.data('endPos'), 'article_id': ui.item.attr('id')};
$.ajax({
data: data,
type: 'POST',
url: '/your/controller/action'
});
}
});
}
});

注:在下一步controller的处理中,我们要使用到acts_as_list rubygem,所以这里只需要传递 移动到了什么位置移动了哪篇文章 两个参数即可,即 end_positionarticle_id

很简单的JS代码,无需过多解释,详细请看jquery-sortable的 API

后端controller sort action的实现

在实现controller action之前,参照这里为你的model的数据表加上“position”的字段,并设置model的scope参数。

在上一步我们获取到JS传递给controller的article_params,例如

1
2
3
...
# raise article_params.inspect
=> {'end_position': "6", 'article_id': 10086}

下一步我们在 articles_controller 中写一个action:

1
2
3
4
5
6
def sort_articles
@article = Article.find(params[:article_id])
@article.insert_at(params[:end_position].to_i)
render :nothing => true
end

这里的“insert_at”请参考这里acts_as_list的API,它提供了reorder list的方法。

定义路由表

当然,由前端发送POST请求,你需要定义一条路由:

1
2
3
4
5
6
...
resources :articles do
...
post "sort-articles" => "articles#sort_articles", on: :collection
end
...

What is more

我们在实现上面所说的基本功能之后,欣喜地发现,在browser上的表现堪称完美。但是在测试过程中又遇到了新的难题:在移动端无法实现排序的功能。为此,我提供了一种解决方案。

jQuery UI Touch Punch

jQuery UI Touch Punch 提供了在移动端实现上述排序功能的小工具,并且使用起来非常方便,按照官网所说,总共分3步(这里我结合RoR来举例,读者可参考上面的link在自己的code中实现):

1、在页面中引用jQuery和jQuery UI的库 - application.js

1
2
3
4
...
//= require jquery
//= require jquery-ui
...

2、引用touch-punch的自定义js库

1
2
3
...
//= require ./vendors/jquery.ui.touch-punch
...

自定义js库的代码在jQuery UI Touch Punch中有提供下载。

3、在你的js代码中应用Touch Punch的方法.draggable() ,我们在此引用上面的js代码

1
2
3
4
5
6
7
$(function () {
if($('.Articles').length) {
$('ol.articles').sortable(...);
// or as below to move the whole article block
$('ol.articles').draggable();
}
});

用你的iPhone来访问你的页面,是不是可以实现拖动了?