Подтвердить что ты не робот

Сортируемые списки 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)

Я искал что-то вроде этого без везения. Возможно ли это??

4b9b3361

Ответ 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/