【问题标题】:Knockout + JQuery sortable = list items disappears淘汰赛 + JQuery 可排序 = 列表项消失
【发布时间】:2016-05-02 20:06:40
【问题描述】:

我已经在网上搜索了好几个小时!

我有一个可淘汰的可观察数组,我可以通过绑定到 jQuery 可排序来重新排列它。除了一个烦人的小错误外,一切正常。

如果我将第二个列表项拖到第一个列表项上方(不拖放),然后返回并将其放到原来的位置,然后将第一个列表项拖放到第二个和第三个之间...第二个列表项消失了!

HTML:

<ul data-bind="foreach: headers, uiSortableList: headers" class="dropdown-menu">
    <li>
        <span data-bind="text: title"></span>
    </li>
</ul>

Javascript:

ko.bindingHandlers.uiSortableList = {
    init: function (element, valueAccessor, allBindingsAccesor, context) {
        var list = valueAccessor();

        $(element).sortable({
            axis: 'y',
            update: function (event, ui) {
                var item = ko.dataFor(ui.item[0]);
                var newIndex = ui.item.index();

                if (list.indexOf(item) != newIndex) {
                    ui.item.remove();
                    list.remove(item);
                    list.splice(newIndex, 0, item);
                }
            }
        });
    }
};

function ViewModel() {
    var self = this;

    self.headers = ko.observableArray([
        {title: 'One'},
        {title: 'Two'},
        {title: 'Three'},
        {title: 'Four'}
    ]);
}

var vm = new ViewModel();
ko.applyBindings(vm);

外部脚本:

https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js
https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js
https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js

JSFiddle:https://jsfiddle.net/connyake/w1Lgqtug/

【问题讨论】:

    标签: jquery jquery-ui knockout.js


    【解决方案1】:

    问题是 observableArray 和 jQuery 都在争夺显示元素的控制权。在这种情况下,您希望 jQuery 控制视图,并将其更改反映到数组中,而不会将中间更改 back 反映到视图中。

    所以不要对 observableArray 进行 removesplice 操作,而是对内容进行操作,然后告诉数组它已经更新。

            update: function (event, ui) {
                var item = ko.dataFor(ui.item[0]);
                var newIndex = ui.item.index();
                var oldIndex = list.indexOf(item);
    
                if (oldIndex != newIndex) {
                    list().splice(oldIndex, 1);
                    list().splice(newIndex, 0, item);
                    list.valueHasMutated();
                }
            }
    

    在下面的示例中,我添加了第二个不可排序的列表,因此您可以看到 observableArray 确实适当地反映了更改。我还添加了一个按钮来创建更多项目,这似乎按预期工作。

    重要提示:在测试中,我有几次两个阵列不同步。如果将二移到一之上,然后将一移到最后一个位置,则 jQuery 列表会被打乱。所以这不是一个完美的解决方案,但它确实确定了您所看到的问题(并且可能仍然是 observableArray 和 jQuery 争夺控制权的问题)。如果我重新排列 jQuery 列表直到它与另一个列表匹配,那么它们会再次同步。

    更新如果你重置 observableArray 的内容,它似乎就不再迷茫了。如果您的列表很长,这不是一个很好的解决方案,因为重绘会很明显,但它似乎确实很健壮。我已将其替换为 sn-p。

        if (oldIndex != newIndex) {
          var c = list();
          list([]);
          c.splice(oldIndex, 1);
          c.splice(newIndex, 0, item);
          list(c);
        }
    

    ko.bindingHandlers.uiSortableList = {
      init: function(element, valueAccessor, allBindingsAccesor, context) {
        var list = valueAccessor();
    
        $(element).sortable({
          axis: 'y',
          update: function(event, ui) {
            var item = ko.dataFor(ui.item[0]);
            var newIndex = ui.item.index();
            var oldIndex = list.indexOf(item);
    
            if (oldIndex != newIndex) {
              var c = list();
              list([]);
              c.splice(oldIndex, 1);
              c.splice(newIndex, 0, item);
              list(c);
            }
          }
        });
      }
    };
    
    function ViewModel() {
      var self = this;
    
      self.headers = ko.observableArray([{
        title: 'One'
      }, {
        title: 'Two'
      }, {
        title: 'Three'
      }, {
        title: 'Four'
      }]);
      self.addItem = function() {
        self.headers.push({
          title: 'Item' + self.headers().length
        });
      };
    }
    
    var vm = new ViewModel();
    console.clear();
    ko.applyBindings(vm);
    ul {
      width: 100px;
    }
    li {
      margin: 2px;
      padding: .2em;
      background-color: #777;
      color: #fff;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <ul data-bind="foreach: headers, uiSortableList: headers" class="dropdown-menu">
      <li>
        <span data-bind="text: title"></span>
      </li>
    </ul>
    <ul data-bind="foreach: headers">
      <li>
        <span data-bind="text: title"></span>
      </li>
    </ul>
    <button data-bind="click: addItem">Add Item
    </button>

    【讨论】:

    • 这似乎工作得很好。我的清单不会那么长(至少一百年左右不会),所以重绘不是问题。非常感谢!
    猜你喜欢
    • 2012-08-29
    • 2012-12-25
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-20
    • 2014-01-24
    • 2017-11-04
    相关资源
    最近更新 更多