【问题标题】:dynamic row creation knockout js动态行创建淘汰赛js
【发布时间】:2013-02-12 21:14:27
【问题描述】:

我正在尝试使用淘汰赛 js 创建一个具有 4 行和 4 列的表。下面是我的数组,它有 16 个元素,需要放入表格中。

    /*----------------------------------------------------------------------*/
/* View Model                                                           */
/*----------------------------------------------------------------------*/
function ViewModel() {
    var self = this;
    self.items = ko.observableArray(["1.jpg", 
                                      "2.jpg", 
                                      "3.jpg", 
                                      "4.jpg",
                                      "5.jpg",
                                      "6.jpg"
                                      ]);
    self.itemRows = ko.computed(function () { //computes the rows dynamically based on items
        var rows = [];
        var count = 0;
        var items = self.items(); //get the item array
        var current = [];
        for(var i in items)
        {
            var item = items[i];
            current.push(item);
            count++;

            if (count == 4)
            {
                count = 0;
                rows.push(current);
                current = []; //next array
            }
        }

        if (current.length > 0)
        {
            rows.push(current);
        }

        return rows;
    });

    self.bindSort = function() {

        var startIndex = -1;         
        var sortableSetup = {        
         start: function (event, ui)
         {         
          startIndex = ui.item.index();
         },


         stop: function (event, ui) 
         {      
          var newIndex = ui.item.index();        
          if (startIndex > -1) 
          {
              self.from = ko.observable(startIndex);
              self.to = ko.observable(newIndex);
              var iTo = parseInt(self.to());
          var iFrom = parseInt(self.from());
          var from = self.items()[iFrom];
              var to = self.items()[iTo];
              self.items()[iTo] = from;
                  self.items()[iFrom] = to;
                  //alert('before');
                  // alert(from);
                  // alert(to);
                  var fromA = self.items()[iFrom];
              var toA = self.items()[iTo]; 
              //alert('after');
          //alert(fromA);
                  // alert(toA);
              self.items.remove(from);               
              self.items.splice(newIndex, 0, toA);
               self.items.remove(to); 
                self.items.splice(startIndex, 0, fromA);
                          //ui.item.remove();
               self.items.valueHasMutated();

          }

         }
        };


        $(".fruitList").sortable( sortableSetup );                           

    };

}   

/*----------------------------------------------------------------------*/
/* KO HTML Binding                                                      */
/*----------------------------------------------------------------------*/   
$(document).ready(function() {

    // create the view model
    var model = new ViewModel();

    // call the bind method for jquery UI setup
    model.bindSort();

    // binds ko attributes with the html
    ko.applyBindings(model);

});

并尝试在 html 中执行此操作,

<table data-bind="foreach: itemRows">
              <tr class="fruitList" data-bind="foreach: $data">
                  <td><img data-bind="attr: { src: $data }" /></td>
              </tr>
        </table>

我无法获得数组的长度,以及如何在第一行创建 4 个 tds 然后创建第二行时打破循环。任何建议???

更新:

当我使用可排序时,下面的代码似乎不起作用,

    start: function (event, ui)
     {         
      startIndex = ui.item.index();
     },


     stop: function (event, ui) 
     {      
      var newIndex = ui.item.index();  

【问题讨论】:

  • 对于循环的“中断”.. 我建议你使用 div 和 position:relative;向左飘浮;它会做同样的事情,只是一开始有点棘手。
  • 我支持@Yoeri 所说的,table、tr、td 结构是强制性的吗?您最终会得到一个更好的解决方案,使用 div 代替并使用 CSS(以及第 n 个子类型选择器)将它们定位在表结构中。
  • @ryadavilli 尝试使用 div 仍然无法正常工作...

标签: javascript arrays knockout.js foreach


【解决方案1】:

更新:可排序版本移至底部

不可排序的版本

在您编辑和提及排序之前,我创建了一个似乎符合您要求的 jsfiddle:http://jsfiddle.net/fENSD/4/

我所做的是创建一个计算的 observable,它观察您的项目 observable 并返回一个嵌套数组,该数组的形状是您想要用于表格渲染的形状。这不是最有效的功能,但通过一些工作,您可能会减少分配的数组数量(目前,每次更新时都会为 4x4 网格创建 5 个左右):

self.items = ko.observableArray(["images/1.jpg", "images/2.jpg", "images/3.jpg", "images/4.jpg", "images/5.jpg", "images/6.jpg"]);

self.itemRows = ko.computed(function () { //computes the rows dynamically based on items
    var rows = [];
    var count = 0;
    var items = self.items(); //get the item array
    var current = [];
    for(var i in items)
    {
        var item = items[i];
        current.push(item);
        count++;

        if (count == 4)
        {
            count = 0;
            rows.push(current);
            current = []; //next array
        }
    }

    if (current.length > 0)
    {
        rows.push(current);
    }

    return rows;
});

然后表格呈现如下:

<table data-bind="foreach: itemRows">
    <tr data-bind="foreach: $data">
        <td><img data-bind="attr: { src: $data }" /></td>
    </tr>
</table>

JSFiddle 包含一个将项目添加到可观察项目的示例,并且如果您想看到它的实际效果,表也会被更新以反映这一点。在 JSFiddle 中还有一个示例,您可以通过一种方式获取 items 数组的长度 (data-bind="text: items().length")。

可排序版本

这是一个相当大的变化,但我设法让排序也正常工作。以jquery ui网站为例,我得到以下信息:

http://jsfiddle.net/fENSD/11/

对表格进行排序非常困难,因此 jquery ui 示例实际上使用了一个列表,该列表具有定义的宽度,每个元素占用一定的宽度。这有效地创建了一个表。我假设由于您使用的是图像,因此您可以使它们的大小完全相同。

为此,我有一些这样的 CSS:

#items { list-style-type: none; margin: 0; padding: 0; width: 200px; }
#items li { width: 48px; margin: 0px; padding: 0px; float: left; text-align: center; height: 48px; }

然后我像这样创建了一个适当的绑定处理程序:

ko.bindingHandlers['sortable'] = {
    init: function (element, valueAccessor) {
        var $element = $(element);
        var observable = valueAccessor();
        var value = ko.utils.unwrapObservable(observable);
        $element.sortable({
            stop: function(event, ui) {
                var prev = ui.item.prev();
                var data = ko.dataFor(ui.item[0]);
                var index = 0;
                if (prev.length > 0) {
                    //not the first item
                    var prevData = ko.dataFor(prev[0]);
                    var index = value.indexOf(prevData) + 1;
                }
                var oldIndex = value.indexOf(data);
                value.splice(oldIndex, 1);
                value.splice(index, 0, data);
                observable.valueHasMutated();
            }
        });
    }
};

每当 sortable 更新时,它都会修改传递给绑定的 observable 数组。 注意:这非常不可靠,需要检查以确保传递的值实际上是可观察的,然后再告诉它它的值已经发生了变化。

视图模型如下所示:

function ViewModel() {
    var self = this;

    self.items = ko.observableArray(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"]);

    self.items.subscribe(function (value) {
        console.log(value); //this is so you can see that the array is indeed being re-sorted
    });

    self.add = function () {
        self.items.push("another thing");
    };
}

然后渲染:

<ul id="items" data-bind="sortable: items, foreach: items">
    <li><img data-bind="attr: { src: $data }" /></li>
</ul>

此方法的局限性在于,如果您的项目大小不同,可排序的顺序看起来与内存中实际表示的顺序略有不同。但是,如果您的所有元素大小相同,它应该可以正常工作。另一个问题是这不适用于重复项目。然而,要解决这个问题,只需让每个元素成为一个包含一个值(甚至可能是一个可观察值)的对象,而不是一个普通的旧字符串。

【讨论】:

  • 谢谢它的工作,但排序似乎不起作用......发布了完整的代码请帮忙......
  • 我完全重写了它来处理排序。它不再使用表格,但确实具有类似表格的格式。
  • 完美运行。但是我想像当我将 1 移动到 12 时那样进行交换, 12 应该到 1 .. 希望你能得到我,就像将一个元素交换到一个目标,并且目标元素应该与被拖动的元素交换..跨度>
  • 交换行为有点困难。默认情况下可排序用于重新排序项目,而不是交换项目。到目前为止,我见过的最优雅的解决方案是可交换插件。这里的主要问题不在于交换(这是一件简单的事情),而在于显示。您可以使用与上面几乎完全相同的代码来交换元素,并且在内存中它看起来会很好,但呈现的列表将不会按照正确的顺序排列。您需要某种占位符对象,以便在拖动项目时不会进行任何排序。
猜你喜欢
  • 2017-05-11
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
  • 2015-05-01
相关资源
最近更新 更多