所谓的 Ajax 拖拉 UI,就是直接用鼠标进行拖拉排序,这种方式对用户来说操作速度更快。
拖拉的 UI 需要额外的前端套件,这里介绍 jQuery UI 的 Sortable Plugin,并直接使用 jquery-ui-rails 这个 gem 来安装
编辑 Gemfile
Gemfile
+ gem 'jquery-ui-rails'
编辑 app/assets/javascripts/admin.js
app/assets/javascripts/admin.js
//= require bootstrap-datepicker/core
//= require bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN
//= require ckeditor/init
+ //= require jquery-ui
编辑 app/assets/stylesheets/admin.scss
,其中 .sortable_icon
是给画面中可被拖拉的 ☰ 的样式
app/assets/stylesheets/admin.scss
+ @import "jquery-ui";
+
+ .sortable .sortable_icon {
+ border: none;
+ color: #ECECEC;
+ font-size: 20px;
+ cursor: move;
+ padding-right: 10px;
+ }
执行 bundle
,重启服务器
编辑 app/views/admin/events/index.html.erb
app/views/admin/events/index.html.erb
<table class="table">
+ <thead>
<tr>
<th><%= check_box_tag "全选", "1", false, :id => "toggle_all" %></th>
<th>Event Name</th>
<th>Actions</th>
</tr>
+ </thead>
+ <tbody class="sortable">
<% @events.each do |event| %>
- <tr>
+ <tr data-reorder-url="<%= reorder_admin_event_path(event) %>">
<td>
<%= check_box_tag "ids[]", event.id %>
</td>
- <td><%= link_to event.name, admin_event_path(event) %></td>
+ <td>
+ <span class="sortable_icon">☰</span>
+ <%= link_to event.name, admin_event_path(event) %>
+ </td>
<td>
- <%= link_to "上移", reorder_admin_event_path(event, :position => :up), :method => :post, :class => "btn btn-default" %>
- <%= link_to "下移", reorder_admin_event_path(event, :position => :down), :method => :post, :class => "btn btn-default" %>
<%= link_to "置顶", reorder_admin_event_path(event, :position => :first), :method => :post, :class => "btn btn-default" %>
<%= link_to "置底", reorder_admin_event_path(event, :position => :last), :method => :post, :class => "btn btn-default" %>
<%= link_to "Tickets", admin_event_tickets_path(event), :class => "btn btn-default" %>
<%= link_to "Edit", edit_admin_event_path(event), :class => "btn btn-default" %>
<%= link_to "Delete", admin_event_path(event), :method => "delete", :data => { :confirm => "Are you sure?" }, :class => "btn btn-danger" %>
</tr>
<% end %>
+ </tbody>
</table>
<p>
<%= select_tag :event_status, options_for_select( Event::STATUS.map{ |s| [t(s, :scope => "event.status"), s] }), :class => "form-control" %>
<%= submit_tag t(:bulk_update), :class => "btn btn-primary" %>
<%= submit_tag t(:bulk_delete), :class => "btn btn-danger", :data => { :confirm => "Are you sure?" } %>
</p>
<% end %>
<script>
$("#toggle_all").click(function(){
if ( $(this).prop("checked") ) {
$("input[name='ids[]']").prop("checked", false);
}
})
+ $( ".sortable" ).sortable({
+ axis: 'y', // 限制只能上下拖拉
+ items: 'tr', // 拖拉整个 tr
+ cursor: 'move', // 变更拖拉时的 icon
+ handle: ".sortable_icon", // 限制只有点 ☰ 才能开始拖拉,砍掉这行的话,会是整个 tr 都可以进行拖拉,你可以试试看
+ stop: function(e, ui){ // 当拖拉结束时,会调用这个方法
+ ui.item.children('td').effect('highlight', {}, 1000)
+ },
+ update: function(e, ui) { // 当拖拉结束并且 DOM 上的位置变更时,会调用这个方法
+ reorder_url = ui.item.data('reorder-url')
+ position = ui.item.index() // 取得顺序
+ $.ajax({
+ type: 'POST',
+ url: reorder_url,
+ dataType: 'json',
+ data: { position: position }
+ })
+ }
+ });
</script>
设计解说:
- 我们将整个 tr 包在 tbody 之中,好让
$( ".sortable" ).sortable
将 tbody 标籤内的 tr 都变成可以拖拉,而不会拖拉到标题列 thead 中的 tr。 - 因为每个活动的 reorder 网址都不同,所以我们将网址放在
data-reorder-url="<%= reorder_admin_event_path(event) %>
之中,这样在 jQuery 里面透过reorder_url = ui.item.data('reorder-url')
就可以取得 Ajax 要送去的网址。
编辑 app/controllers/admin/events_controller.rb
app/controllers/admin/events_controller.rb
def reorder
@event = Event.find_by_friendly_id!(params[:id])
@event.row_order_position = params[:position]
@event.save!
- redirect_to admin_events_path
+ respond_to do |format|
+ format.html { redirect_to admin_events_path }
+ format.json { render :json => { :message => "ok" }}
+ end
end