JQuery 可排序列表和固定/锁定项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4299241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JQuery sortable lists and fixed/locked items
提问by laroma
Is it possible to lock list items in JQuery sortable list in a way that those items will stay in that particular place in the list.
是否可以以某种方式锁定 JQuery 可排序列表中的列表项,使这些项保留在列表中的特定位置。
For example,
例如,
consider this pseudo list with locked items...
考虑这个带有锁定项目的伪列表......
item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)
So, I'd like to have the items B,C and G to be fixed in a way that if user drag and drop item D at the start of the list, the item A "jumps" over fixed/locked items B and C with following results...
因此,我希望以某种方式修复项目 B、C 和 G,如果用户在列表开头拖放项目 D,则项目 A“跳过”固定/锁定的项目 B 和 C有以下结果...
item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)
I've been searching for something like this without luck. Is it possible..?
我一直在寻找这样的东西而没有运气。是否可以..?
采纳答案by Gergely Fehérvári
I extended the jQuery.Ui.sortable
:
我扩展了jQuery.Ui.sortable
:
Overview
概述
jQuery.Ui.sortable
widget extension with fixed
feature. This feature allows user to fix elements in the list.
With the .fixedsortable()
constructor you construct a .sortable()
class which extended with the features. You can use the originalmethods and the extendedas well.
jQuery.Ui.sortable
具有fixed
功能的小部件扩展。此功能允许用户修复列表中的元素。
使用.fixedsortable()
构造函数,您可以构建一个.sortable()
扩展了功能的类。您可以使用原始方法和扩展方法。
Code
代码
https://gist.github.com/3758329#file_fixedsortable.js> fixedsortable.js
https://gist.github.com/3758329#file_fixedsortable.js>fixedsortable.js
Example
例子
http://jsfiddle.net/omnosis/jQkdb/
http://jsfiddle.net/omnosis/jQkdb/
Usage
用法
General:
一般的:
To use, add the fixed
property to the sortable list optios:
要使用,请将fixed
属性添加到可排序列表选项中:
$("#list").fixedsortable({
fixed: (value)
})
the value can be:
该值可以是:
- integerexample:
3
- arrayof integers example :
[1,2,5]
- a html elementor a list of html elements
- a css selector
- jqueryobject
- 整数示例:
3
- 整数数组示例:
[1,2,5]
- 一个html 元素或一个 html 元素列表
- 一个CSS 选择器
- jquery对象
HTML:
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
Javascript
$(function() {
$("#sortable1").fixedsortable({
fixed: "> .static"
});
$("#sortable2").fixedsortable({
fixed: $("li[foo]").css("background","red")
});
$("#sortable3").fixedsortable({
fixed: 2
})
});
Notes:
笔记:
If you insist to use the .sortable
instead of .fixedsortable
you can use this https://gist.github.com/3758329#file_sortable.jsinstead of the jquery.ui library. This is a complete replacement of the jQuery.ui
, but i don't recommend to use this because of later updates.
如果你坚持使用.sortable
而不是.fixedsortable
你可以使用这个https://gist.github.com/3758329#file_sortable.js而不是 jquery.ui 库。这是对 的完全替代jQuery.ui
,但由于以后的更新,我不建议使用它。
i have been working on this more than 12 hours :( i am insane..
我已经为此工作了超过 12 个小时:( 我疯了..
回答by DarthJDG
Here's a hopefully bug-free version, updating as you drag. It's generating the current desired positions of the items when sorting starts, which means you should be able to change the classes whenever you need, refresh the widget's list items and you're good to go.
这是一个希望无错误的版本,随着您的拖动而更新。它在排序开始时生成项目的当前所需位置,这意味着您应该能够在需要时更改类,刷新小部件的列表项目,您就可以开始了。
It also uses the sortable's built-in items
property to prevent dragging the fixed items and to sort out any sorting problems at the top and the bottom of the list.
它还使用 sortable 的内置items
属性来防止拖动固定项目并整理列表顶部和底部的任何排序问题。
I tried to move the fixed items around, but that resulted in horribly buggy behaviour, especially when there are multiple fixed items in groups. The final solution detaches all fixed items from the list, adds a helper element to the front, then re-inserts the fixed elements to their desired position, which seems to fix all bugs.
我试图移动固定项目,但这导致了可怕的错误行为,尤其是当组中有多个固定项目时。最终的解决方案是将所有固定项从列表中分离出来,在前面添加一个辅助元素,然后将固定元素重新插入到他们想要的位置,这似乎修复了所有错误。
Try the demo here: http://jsfiddle.net/PQrqS/1/
在此处尝试演示:http: //jsfiddle.net/PQrqS/1/
HTML:
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:
CSS:
.static { color:red; }
li { background-color:whitesmoke; border:1px solid silver; width:100px; padding:2px; margin:2px; }
Javascript:
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();
}
});
回答by Thomas Shields
Check this out: Forcing an item to remain in place in a jQuery UI Sortable list
看看这个:强制一个项目保持在 jQuery UI 可排序列表中的位置
Also, I've implemented the above solution with multiple fixed elements here: http://jsfiddle.net/enBnH/12/(obsolete, see below) It's rather self-explanatory, i think.
EDIT:
I've automated the process for generating the lockto values as well as adding ID's to those li
s with the class "fixed" (note that i have to add an ID so we can reference it)
此外,我已经在这里使用多个固定元素实现了上述解决方案:http: //jsfiddle.net/enBnH/12/(已过时,见下文)我认为这是不言自明的。
编辑:
我已经自动化了生成 lockto 值的过程,以及将 ID 添加到li
具有“固定”类的那些s(请注意,我必须添加一个 ID,以便我们可以引用它)
See the COMPLETE solution HERE: http://jsfiddle.net/enBnH/44/
在此处查看完整的解决方案:http: //jsfiddle.net/enBnH/44/
EDIT
编辑
Okay, after a gazillion errors with the above, i just rewrote the dang thing myself: http://jsfiddle.net/thomas4g/GPMZZ/15/
好的,在上面出现了无数错误之后,我自己重写了该死的东西:http: //jsfiddle.net/thomas4g/GPMZZ/15/
NOTE: The above does work, but @DarthJDG's answer seems a lot nicer to me. I'm leaving mine up on the offchance someone might prefer how mine behaves (i've learned not to delete stuff just beceause there's a better version :P )
注意:以上确实有效,但@DarthJDG 的回答对我来说似乎更好。我让我的人可能更喜欢我的行为方式(我已经学会了不要删除东西只是因为有更好的版本:P)
回答by sarunast
This is based on @DarthJDG code. However it wasn't retrieving all the id's and the sorting wasn't working with the table. So I managed to update his solution which works with both list and tables and keeps the id in the array.
这是基于@DarthJDG 代码。然而,它没有检索所有的 id,并且排序不适用于表。所以我设法更新了他的解决方案,该解决方案适用于列表和表格,并将 id 保留在数组中。
Javascript:
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();
}
});
回答by Leniel Maccaferri
Using the itemsparameter you can achieve what you want like this:
使用items参数,您可以像这样实现您想要的:
$("#mytable tbody").sortable({items: 'tr.sortable'});
Only rows with a .sortable
CSS class can be sorted now.
现在只能对具有.sortable
CSS 类的行进行排序。
If you want to lock only the 1st row you can do this:
如果您只想锁定第一行,您可以这样做:
$("#mytable tbody").sortable({items: 'tr:not(:first)'});
The possibilities are endless...
可能性是无止境...
回答by Ilya Shashilov
Connected sortables and fixed items
连接的可排序项和固定项
I ran into the problem when we have several connected sortables. The code suggested by @sarunast and @DarthJDG has erroneous behavior when dragging items from one list to another. Therefore, I have modified it a little, and now you can drag items from different lists with saving positions in both of them.
当我们有几个连接的 sortables 时,我遇到了这个问题。将项目从一个列表拖到另一个列表时,@sarunast 和 @DarthJDG 建议的代码有错误的行为。因此,我对它进行了一些修改,现在您可以从不同的列表中拖动项目,并在两个列表中保存位置。
javascript:
javascript:
let connected = '.soratble';
let fixed = '.static';
let newParentContainer;
//wrap the code suggested by @sarunast and @DarthJDG into the function
//code was modified a little
function sortingAroundFixedPositions(container) {
let sortable = $(container);
let statics = $(fixed, container).detach();
let tagName = statics.prop('tagName');
let helper = $('<' + tagName + '/>').prependTo(container);
statics.each(function() {
let target = this.dataset.pos;
let targetPosition = $(tagName, sortable).eq(target);
if (targetPosition.length === 0) {
targetPosition = $(tagName, sortable).eq(target - 1)
}
$(this).insertAfter(targetPosition);
});
helper.remove();
}
$('ul').sortable({
connectWith: connected,
cancel: fixed,
start: function() {
$(fixed, connected).each(function() {
this.dataset.pos = $(this).index();
});
},
change: function(e, ui) {
sortingAroundFixedPositions(this);
if (ui.sender) {
newParentContainer = this;
}
if (newParentContainer) {
sortingAroundFixedPositions(newParentContainer);
}
},
update: function(e, ui) {
newParentContainer = undefined;
}
});
回答by monkeyhouse
oh no! gist link is broken. here is code dump from https://gist.github.com/peterh-capella/4234752
不好了!要点链接已损坏。这是来自https://gist.github.com/peterh-capella/4234752 的代码转储
code accessed Jan 6, 2016
代码于 2016 年 1 月 6 日访问
//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's 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's determine the parent's 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's higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's 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);
And dumping rest of his answer, just in case
并丢弃他的其余答案,以防万一
dependencies
依赖
https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.jshttps://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js
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
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
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;
}
回答by Ozsvar Istvan
Maybe this will help to someone: use methods "disable" and "enable". Example HTML:
也许这会对某人有所帮助:使用“禁用”和“启用”方法。示例 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');
});
Live example here: https://jsfiddle.net/ozsvar/0ggqtva5/2/