【问题标题】:Create grid with knockoutjs使用 knockoutjs 创建网格
【发布时间】:2015-01-25 20:44:06
【问题描述】:

假设我们有一个 N+1 个元素的可观察数组。我想要实现的是使用来自这些元素的按钮构建 3 x X 网格。比如手机键盘之类的。

到目前为止,我所做的是创建了一个带有 foreach 的表,如果在其中:

<table>
    <tbody data-bind="foreach: tableList">
<!-- ko if: isEof($index())  -->
        <tr>
<!-- /ko -->
            <td><button data-bind="text: name"></button></td>
<!-- ko if: isEof($index())  -->
        </tr>
<!-- /ko -->
    </tbody>
</table>

isEof() 函数应该通过列表索引确定我们是否已经渲染了 3 个元素。如果是,那么它将呈现标签。此外,如果 index 为 0,那么它也会渲染元素。 这是函数的代码:

function TableItem(data){
    this.id=ko.observable(data.id);
    this.name=ko.observable(data.name);
    this.isEof = function(index){
        if(index ==0){
            return true;
        }else{
            if((index+3) % 3 === 0){
                return true;
            }else{
                return false;
            }
        }
    }
}

但是这个设置我面临两个问题。

1) 启用这些 if 块后,按钮名称绑定不起作用。当我删除 ko if 块时,它将正确呈现。

2) ko if 语句似乎无法正常工作。它只会渲染出那些也允许渲染的行。

我已经制作了我的解决方案的 JSFiddle 示例:http://jsfiddle.net/kpihus/3Lw7xjae/2/

【问题讨论】:

  • 好的,我已经注意到我的问题了。例如,当我有第三个元素时,我将为同一个 元素渲染 和 ,因此其他单元格不在 和 之间。虽然我还不确定,如何解决这个问题。
  • kpilhus 您可以查看现在发布的答案。干杯

标签: javascript knockout.js


【解决方案1】:

我会创建一个ko.computed,它将您的表格项目列表转换为数组数组:

var TableItem = function TableItem(data) {
    this.id   = ko.observable(data.id);
    this.name = ko.observable(data.name);
};

var Vm = function Vm() {
    this.tableItems  = ko.observableArray([]);
    this.columnCount = ko.observable(3);

    this.columns = ko.computed(function() {
        var columns     = [],
            itemCount   = this.tableItems().length,
            begin       = 0;

        // we use begin + 1 to compare to length, because slice 
        // uses zero-based index parameters
        while (begin + 1 < itemCount) {
            columns.push( this.tableItems.slice(begin, begin + this.columnCount()) );
            begin += this.columnCount();
        }

        return columns;

    // don't forget to set `this` inside the computed to our Vm
    }, this);
};

vm = new Vm();

ko.applyBindings(vm);

for (var i = 1; i < 15; i++) {
    vm.tableItems.push(new TableItem({
        id: i,
        name: "name: " + i
    }));
}

这样,您可以通过嵌套两个foreach 绑定来显示您的表格:

<table>
    <tbody data-bind="foreach: { data: columns, as: 'column' }">
        <tr data-bind="foreach: column">
            <td>
                <button data-bind="text: name">A</button>
            </td>
        </tr>
    </tbody>
</table>

JSFiddle

如果您之前没有使用过ko.computed,它们会跟踪在它们内部访问的任何可观察对象——在本例中为this.tableItemsthis.columnCount——并且每当其中一个发生变化时,它们就会再次运行并生成一个新的结果。

this.columns 获取我们的表格项数组

[TableItem, TableItem, TableItem, TableItem, TableItem, TableItem]

并按this.columnCount 将它们分组到

[[TableItem, TableItem, TableItem], [TableItem, TableItem, TableItem]]

【讨论】:

  • janfoeh 好吧,我发布了一个答案,但我可以避免从视图中传递root 吗?有没有办法我可以在isEof 函数中获取父数组?尝试了 contextFor & dataFor 我在那里未定义。我想让我的视野更干净。谢谢
  • @supercool 每当你发现自己玩弄范围太多时,很有可能你问了错误的对象错误的问题——一个人 TableItem 本身不知道它是否是第三项a 表项列表。与其像在此处那样尝试通过授予它访问范围的权限来解决此问题,为什么不询问父对象(此处的视图模型)已经可以访问列表并且可以弄清楚呢?至于undefined,你试过dataFor还是ko.dataFor
  • 我试过了,但 vm.tableList 给了我 undefined 。 ko.dataFor() 也给了我 undefined 。我不太明白为什么 dataFor 不起作用?它是否仅限于单击我们获得this以作为参数传递的位置。你可以试试我的小提琴看看问题。再次感谢
  • ko.dataFor 需要一个 HTML 元素作为其参数。你是从哪里给ko.dataFor打电话的?
  • self.isEof 内我尝试访问它,因为我需要那个父数组列表。目前我正在通过 root 作为函数的参数。
【解决方案2】:

我们可以通过简单地传递$root 来实现这一点,它将具有tableList 并以简单的方式进行循环。

查看模型:

function TableItem(data) {
    var self = this;
    self.id = ko.observable(data.id);
    self.name = ko.observable(data.name);
    self.pickarray = ko.observableArray();
    self.isEof = function (index, root) {
        if (index === 0) {
            self.pickarray(root.tableList().slice(index, index + 3));
            return true;
        } else if ((index + 3) % 3 === 0) {
            self.pickarray(root.tableList().slice(index, index + 3));
            return true;
        } else {
            return false;
        }
    }
}

var vm = function () {
    this.tableList = ko.observableArray();
    for (var i = 1; i < 15; i++) {
        this.tableList.push(new TableItem({
            id: i,
            name: "name: " + i
        }));
    }
}

ko.applyBindings(new vm());

查看:

<table data-bind="foreach:tableList">
    <tr data-bind="if:isEof($index(),$root)">
        <!-- ko foreach: pickarray -->
        <td>
            <button data-bind="text: id"></button>
        </td>
        <!-- /ko -->
    </tr>
</table>

这里的技巧非常简单,我们只需要有条件地填写 pickarray 即可。

工作小提琴here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多