Сортируемые списки JQuery и фиксированные/заблокированные элементы
Можно ли заблокировать элементы списка в отсортированном списке JQuery таким образом, чтобы эти элементы оставались в этом конкретном месте в списке.
Например,
рассмотрите этот псевдо-список с заблокированными элементами...
item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)
Итак, я хотел бы, чтобы элементы B, C и G фиксировались таким образом, что если пользователь перетаскивает элемент D в начале списка, элемент A "перескакивает" по фиксированным/заблокированным элементам B и C со следующими результатами...
item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)
Я искал что-то вроде этого без везения. Возможно ли это??
Ответы
Ответ 1
Я расширил jQuery.Ui.sortable
:
Обзор
jQuery.Ui.sortable
расширение с помощью fixed
. Эта функция позволяет пользователю фиксировать элементы в списке.
С конструктором .fixedsortable()
вы создаете класс .sortable()
, который расширяется с помощью функций. Вы можете использовать методы оригинал и расширенный.
код
https://gist.github.com/3758329#file_fixedsortable.js > fixedsortable.js
Пример
http://jsfiddle.net/omnosis/jQkdb/
Использование
Общие:
Чтобы использовать, добавьте свойство fixed
в список сортируемых списков:
$("#list").fixedsortable({
fixed: (value)
})
значение может быть:
- целочисленный пример:
3
- массив примера целых чисел:
[1,2,5]
- a элемент html или список элементов html
- a селектор css
- объект jquery
HTML:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> //the jquery
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script> //the original jquery-ui
<script type="text/javascript" src="https://raw.github.com/gist/3758329/91749ff63cbc5056264389588a8ab64238484d74/fixedsortable.js"></script> //the extended sortable
...
<ul id="sortable1">
<li>oranges</li>
<li class="static">apples</li>
<li>bananas</li>
<li>pineapples</li>
<li>grapes</li>
<li class="static">pears</li>
<li>mango</li>
</ul>
<ul id="sortable2">
<li>bananas</li>
<li foo="asd">oranges</li>
<li foo="dsa">apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
<ul id="sortable3">
<li>bananas</li>
<li>oranges</li>
<li>apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
Javascript
$(function() {
$("#sortable1").fixedsortable({
fixed: "> .static"
});
$("#sortable2").fixedsortable({
fixed: $("li[foo]").css("background","red")
});
$("#sortable3").fixedsortable({
fixed: 2
})
});
Примечания:
Если вы настаиваете на использовании .sortable
вместо .fixedsortable
, вы можете использовать эту https://gist.github.com/3758329#file_sortable.js вместо библиотеки jquery.ui. Это полная замена jQuery.ui
, но я не рекомендую использовать это из-за более поздних обновлений.
Я работал над этим более 12 часов:( Я сумасшедший..
Ответ 2
Здесь, надеюсь, бесплатная версия, обновляющаяся при перетаскивании. Он генерирует текущие желаемые позиции элементов при запуске сортировки, что означает, что вы должны иметь возможность изменять классы всякий раз, когда вам нужно, обновлять элементы списка виджетов, и вам хорошо идти.
Он также использует сортируемое встроенное свойство items
, чтобы предотвратить перетаскивание фиксированных элементов и сортировать любые проблемы сортировки в верхней и нижней частях списка.
Я пытался перемещать фиксированные элементы вокруг, но это приводило к ужасно ошибочному поведению, особенно когда в группах имеется несколько фиксированных элементов. Окончательное решение отделяет все фиксированные элементы от списка, добавляет вспомогательный элемент на передний план, затем повторно вставляет фиксированные элементы в нужное положение, что, кажется, исправляет все ошибки.
Попробуйте демо здесь: http://jsfiddle.net/PQrqS/1/
HTML:
<ul id="sortable">
<li>oranges</li>
<li class="static">apples</li>
<li>bananas</li>
<li>pineapples</li>
<li>grapes</li>
<li class="static">pears</li>
<li>mango</li>
</ul>
CSS
.static { color:red; }
li { background-color:whitesmoke; border:1px solid silver; width:100px; padding:2px; margin:2px; }
JavaScript:
$('#sortable').sortable({
items: ':not(.static)',
start: function(){
$('.static', this).each(function(){
var $this = $(this);
$this.data('pos', $this.index());
});
},
change: function(){
$sortable = $(this);
$statics = $('.static', this).detach();
$helper = $('<li></li>').prependTo(this);
$statics.each(function(){
var $this = $(this);
var target = $this.data('pos');
$this.insertAfter($('li', $sortable).eq(target));
});
$helper.remove();
}
});
Ответ 3
Отметьте это: Принуждение элемента к месту в списке сортировки пользовательского интерфейса jQuery
Кроме того, я реализовал вышеупомянутое решение с несколькими фиксированными элементами здесь: http://jsfiddle.net/enBnH/12/ (устаревший, см. ниже)
Я думаю, что это довольно самоочевидно.
EDIT:
Я автоматизировал процесс генерации значений lockto, а также добавил идентификатор к этим li
с классом "fixed" (обратите внимание, что мне нужно добавить идентификатор, чтобы мы могли ссылаться на него)
См. решение COMPLETE ЗДЕСЬ: http://jsfiddle.net/enBnH/44/
ИЗМЕНИТЬ
Хорошо, после gazillion ошибок с выше, я просто переписал вещь dang себя:
http://jsfiddle.net/thomas4g/GPMZZ/15/
ПРИМЕЧАНИЕ. Вышеизложенное работает, но ответ @DarthJDG кажется мне намного приятнее. Я ухожу из-под контроля, кто-то может предпочесть, как ведет себя моя (я научился не удалять вещи, просто потому, что там есть лучшая версия: P)
Ответ 4
Используя параметр items, вы можете добиться того, чего хотите:
$("#mytable tbody").sortable({items: 'tr.sortable'});
Теперь можно отсортировать только строки с классом CSS .sortable
.
Если вы хотите заблокировать только 1-ю строку, вы можете сделать это:
$("#mytable tbody").sortable({items: 'tr:not(:first)'});
Возможности бесконечны...
Ответ 5
Это основано на коде @DarthJDG. Однако он не извлекал весь идентификатор, и сортировка не работала с таблицей. Поэтому мне удалось обновить его решение, которое работает как с списком, так и с таблицами и сохраняет идентификатор в массиве.
JavaScript:
var fixed = '.static'; //class which will be locked
var items = 'li'; //tags that will be sorted
$('ul').sortable({
cancel: fixed,
items: items,
start: function () {
$(fixed, this).each(function () {
var $this = $(this);
$this.data('pos', $this.index());
});
},
change: function () {
var $sortable = $(this);
var $statics = $(fixed, this).detach();
var tagName = $statics.prop('tagName');
var $helper = $('<'+tagName+'/>').prependTo(this);
$statics.each(function () {
var $this = $(this);
var target = $this.data('pos');
$this.insertAfter($(items, $sortable).eq(target));
});
$helper.remove();
}
});
Демо: http://plnkr.co/edit/hMeIiRFT97e9FGk7hmbs
Ответ 6
о нет! Существующая связь нарушена. здесь дамп кода из https://gist.github.com/peterh-capella/4234752
доступ к коду 6 января 2016 года
//this code is created to fix this problem: http://stackoverflow.com/questions/4299241/
(function( $, undefined ) {
$.widget("ui.fixedsortable", $.ui.sortable, {
options: $.extend({},$.ui.sortable.prototype.options,{fixed:[]}),
_create: function() {
var o = this.options;
this.containerCache = {};
this.element.addClass("ui-sortable");
//Get the items
$.ui.sortable.prototype.refresh.apply(this,arguments);
if( typeof this.options.fixed == "number") {
var num = this.options.fixed
this.options.fixed = [num];
}
else if( typeof this.options.fixed == "string" || typeof this.options.fixed == "object") {
if(this.options.fixed.constructor != Array) {
var selec = this.options.fixed;
var temparr = [];
var temp = $(this.element[0]).find(selec);
var x = this;
temp.each(function() {
var i;
for(i=0;i<x.items.length && x.items[i].item.get(0) != this;++i) {}
if(i<x.items.length) temparr.push(i);
});
this.options.fixed = temparr;
}
}
//Let determine if the items are being displayed horizontally
this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
//Let determine the parent offset
this.offset = this.element.offset();
//Initialize mouse events for interaction
$.ui.sortable.prototype._mouseInit.apply(this,arguments);
},
_mouseCapture: function( event ) {
this._fixPrev = this._returnItems();
return $.ui.sortable.prototype._mouseCapture.apply(this,arguments);
},
_mouseStart: function( event ) {
for(var i=0;i<this.options.fixed.length;++i) {
var num = this.options.fixed[i];
var elem = this.items[num];
if(event.target == elem.item.get(0)) return false;
}
return $.ui.sortable.prototype._mouseStart.apply(this,arguments);
},
_rearrange: function(event, i, a, hardRefresh) {
a ? a[0].appendChild(this.placeholder[0]) :
i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
this._refix(i);
//Various things done here to improve the performance:
// 1. we create a setTimeout, that calls refreshPositions
// 2. on the instance, we have a counter variable, that get higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout, if it still the same
// 4. this lets only the last addition to the timeout stack through
this.counter = this.counter ? ++this.counter : 1;
var self = this, counter = this.counter;
window.setTimeout(function() {
if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
},0);
},
_refix: function(a) {
var prev = this._fixPrev;
var curr = this._returnItems();
var Fixcodes = this.options.fixed;
var NoFixed = [];
var Fixed = [];
var Mixed = []
var post = [];
for(var i=0;i<Fixcodes.length;++i) {
var fix_index = Fixcodes[i];
var fix_item = prev[fix_index];
var j = 0;
for(j=0;j<curr.length && curr[j].item.get(0) != fix_item.item.get(0);++j) {}
curr.splice(j,1);
Fixed.push(fix_item);
}
for(var i=0;i<curr.length;++i) {
if(curr[i].item.get(0) != this.currentItem.get(0)) {
NoFixed.push(curr[i]);
}
}
var fix_count = 0;
var nofix_count = 0;
for(var i=0;i<Fixed.length + NoFixed.length;++i) {
if(Fixcodes.indexOf(i) >= 0) {
Mixed.push(Fixed[fix_count++]);
}
else {
Mixed.push(NoFixed[nofix_count++]);
}
}
var parent = this.currentItem.get(0).parentNode;
var allchild = parent.children;
for(var i=0;i<Mixed.length;++i) {
parent.removeChild(Mixed[i].item.get(0));
parent.appendChild(Mixed[i].item.get(0));
}
},
_returnItems: function(event) {
this.containers = [this];
var items = [];
var self = this;
var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
var connectWith = $.ui.sortable.prototype._connectWith.apply;
if(connectWith) {
for (var i = connectWith.length - 1; i >= 0; i--){
var cur = $(connectWith[i]);
for (var j = cur.length - 1; j >= 0; j--){
var inst = $.data(cur[j], 'sortable');
if(inst && inst != this && !inst.options.disabled) {
queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
this.containers.push(inst);
}
};
};
}
for (var i = queries.length - 1; i >= 0; i--) {
var targetData = queries[i][1];
var _queries = queries[i][0];
for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
var item = $(_queries[j]);
item.data('sortable-item', targetData); // Data for target checking (mouse manager)
items.push({
item: item,
instance: targetData,
width: 0, height: 0,
left: 0, top: 0
});
};
};
return items;
},
value: function(input) {
//console.log("test");
$.ui.sortable.prototype.value.apply(this,arguments);
}
});
})(jQuery);
И сбросив остальную часть своего ответа, на всякий случай
зависимостей
https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js
https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js
Script
function randomColor() { //for a little fun ;)
var r = (Math.floor(Math.random()*256));
var g = (Math.floor(Math.random()*256));
var b = (Math.floor(Math.random()*256));
return "#" + r.toString(16) + g.toString(16) + b.toString(16)
}
$(function() {
$("#sortable1").fixedsortable({
fixed: "> .static", //you can use css selector
sort: function() { //you can add events as well, without getting confused. for example:
$(".static").css("background",randomColor()) //change the fixed items background
},
change: function(event,ui) {
$(ui.item[0]).css("border","2px solid "+randomColor()) //change the captured border color
},
stop: function(event,ui) {
$(ui.item[0]).css("border","2px solid #777"); //change the back the css modifications
$("#sortable1 > li.static").css("background","#aaa");
}
});
$("#sortable2").fixedsortable({ //you can use jQuery object as selector
fixed: $("li[foo]").css("background","red")
});
$("#sortable3").fixedsortable({
fixed: [2,4], //you can use array of zero base indexes as selector
update: function(event, ui) {
alert($(this).fixedsortable('toArray')) //the fixedsortable('toArray') also works
}
})
$("#sortable4").fixedsortable({
fixed: 5 //you can fix a single item with a simple integer
})
});
HTML
<body>
<div style="width:120px;float:left;">
<ul id="sortable1">
<li><a href="#">oranges</a></li>
<li class="static"><a href="#">apples</a></li>
<li><a href="#">bananas</a></li>
<li><a href="#">pineapples</a></li>
<li><a href="#">grapes</a></li>
<li class="static"><a href="#">pears</a></li>
<li><a href="#">mango</a></li>
</ul>
<ul id="sortable2">
<li>bananas</li>
<li foo="asd">oranges</li>
<li foo="dsa">apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
</div>
<div style="width:120px;float:left;">
<ul id="sortable3">
<li id="fru_1">bananas</li>
<li id="fru_2">oranges</li>
<li id="fru_3" style="background:#f4f">apples</li>
<li id="fru_4">pineapples</li>
<li id="fru_5" style="background:#faaba9">grapes</li>
<li id="fru_6">pears</li>
<li id="fru_7">mango</li>
</ul>
<ul id="sortable4">
<li>bananas</li>
<li>oranges</li>
<li>apples</li>
<li>pineapples</li>
<li>grapes</li>
<li style="background:#dada00">pears</li>
<li>mango</li>
</ul>
</div>
</body>
CSS
ul {margin:10px;}
ul#sortable1 > li, ul#sortable2 > li, ul#sortable3 > li, ul#sortable4 > li {
display:block;
width:100px;
height:15px;
padding: 3px;
background: #aaa;
border: 2px solid #777;
margin: 1px;
}
ul#sortable1 > li.static {
opacity:0.5;
}
Ответ 7
Возможно, это кому-то поможет: используйте методы "отключить" и "включить". пример
HTML:
<ul class="sortable">
<li>You can move me</li>
<li data-state="lifeless">You can't move me.</li>
</ul>
Script:
$('#sortable').sortable();
$('#sortable').mousedown(function() {
if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
else $('#sortable').sortable('enable');
});
Здесь показан живой пример: https://jsfiddle.net/ozsvar/0ggqtva5/2/