Сортируемые списки JQuery и фиксированные / заблокированные элементы - PullRequest
30 голосов
/ 29 ноября 2010

Можно ли заблокировать элементы списка в сортируемом списке 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)

Я искал что-то подобное без удачи.Возможно ли это? ..

Ответы [ 8 ]

58 голосов
/ 26 мая 2011

Надеюсь, это версия без ошибок, которая обновляется при перетаскивании.Он генерирует текущие желаемые позиции элементов при запуске сортировки, что означает, что вы должны иметь возможность изменять классы, когда вам нужно, обновлять элементы списка виджета, и все готово.

Он также используетВстроенное свойство sortable 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();
    }
});
26 голосов
/ 26 мая 2011

Я расширил 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 часов :( Я безумен..

9 голосов
/ 24 мая 2011

Проверьте это: Принудительное сохранение элемента в списке сортировки пользовательского интерфейса jQuery

Также я реализовал вышеупомянутое решение с несколькими фиксированными элементами здесь: http://jsfiddle.net/enBnH/12/ (устарело, см. Ниже) Я думаю, это довольно очевидно.

EDIT:

Я автоматизировал процесс генерации значений lockto, а также добавления идентификаторов к этим li с классом «fixed» (обратите внимание, что мне нужно добавить идентификатор, чтобы мы могли ссылаться на него)

См. ПОЛНОЕ решение ЗДЕСЬ: http://jsfiddle.net/enBnH/44/

EDIT

Хорошо, после множества ошибок с вышеперечисленным, я просто переписал чертову вещь сам: http://jsfiddle.net/thomas4g/GPMZZ/15/

ПРИМЕЧАНИЕ. Вышеуказанное работает, но ответ @ DarthJDG кажется мне намного приятнее. Я оставляю свою на случай, когда кто-то может предпочесть, как ведет себя мой (я научился не удалять вещи, просто потому, что есть лучшая версия: P)

4 голосов
/ 27 июня 2014

Это основано на коде @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

3 голосов
/ 24 января 2014

Используя параметр items , вы можете достичь желаемого:

$("#mytable tbody").sortable({items: 'tr.sortable'});

Теперь можно сортировать только строки с классом CSS .sortable.

Если вы хотите заблокировать только 1-й ряд, вы можете сделать это:

$("#mytable tbody").sortable({items: 'tr:not(:first)'});

Возможности бесконечны ...

1 голос
/ 13 марта 2018

Связанные сортируемые и фиксированные элементы

Я столкнулся с проблемой, когда у нас есть несколько связанных сортировок. Код, предложенный @sarunast и @DarthJDG, имеет ошибочное поведение при перетаскивании элементов из одного списка в другой. Поэтому я немного его изменил, и теперь вы можете перетаскивать элементы из разных списков, сохраняя позиции в них обоих.

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;
  }
});

демо: http://plnkr.co/edit/blmv4ZjaWJFcjvO2zQH0

0 голосов
/ 27 июня 2016

Может быть, это кому-нибудь поможет: используйте методы «отключить» и «включить».Пример HTML:

<ul class="sortable">
  <li>You can move me</li>
  <li data-state="lifeless">You can't move me.</li>
</ul>

Сценарий:

$('#sortable').sortable();
$('#sortable').mousedown(function() {
  if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
  else $('#sortable').sortable('enable');
});

Живой пример здесь: https://jsfiddle.net/ozsvar/0ggqtva5/2/

0 голосов
/ 07 января 2016

о нет!Суть ссылки не работает.вот дамп кода из https://gist.github.com/peterh-capella/4234752

кода, к которому получен доступ 6 января 2016 года

//this code is created to fix this problem: /4071163/sortiruemye-spiski-jquery-i-fiksirovannye-zablokirovannye-elementy

(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);

И вывод остатка его ответа, на случай

зависимостей

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

Скрипт

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;
}
...