【问题标题】:Knockout.js binding does not work while working with collections使用集合时,Knockout.js 绑定不起作用
【发布时间】:2016-03-11 00:38:34
【问题描述】:

我是 Knockoutjs 的初学者。在使用集合时,在我看来绑定不起作用(显示文本,但在值更新后未更新)。例如以下代码:

<h2>People</h2>
<ul data-bind="foreach: people">
    <li>
        <div>          
            <span data-bind="text: name"> </span> has <span data-bind='text: children().length'>&nbsp;</span> children:
            <a href='#' data-bind='click: addChild '>Add child</a>
            <span class='renderTime' data-bind='visible: $root.showRenderTimes'>
                (person rendered at <span data-bind='text: new Date().getSeconds()' > </span>)
            </span>
        </div>
        <ul data-bind="foreach: children">
            <li>
              <input type="text" data-bind="value: $data">
                <span data-bind="text: $data"> </span>
                <span class='renderTime' data-bind='visible: $root.showRenderTimes'>
                    (child rendered at <span data-bind='text: new Date().getSeconds()' > </span>)
                </span>
            </li>
        </ul>
    </li>
</ul>
<label><input data-bind='checked: showRenderTimes' type='checkbox' /> Show render times</label> 

这是官方 Knockout.js 网站上的示例代码 http://knockoutjs.com/examples/collections.html 源js代码是这样的:

// Define a "Person" class that tracks its own name and children, and has a method to add a new child
var Person = function(name, children) {
    this.name = name;
    this.children = ko.observableArray(children); 
    this.addChild = function() {
        this.children.push("New child");
    }.bind(this);
} 
// The view model is an abstract description of the state of the UI, but without any knowledge of the UI technology (HTML)
var viewModel = {
    people: [
        new Person("Annabelle", ["Arnie", "Anders", "Apple"]),
        new Person("Bertie", ["Boutros-Boutros", "Brianna", "Barbie", "Bee-bop"]),
        new Person("Charles", ["Cayenne", "Cleopatra"])
    ],
    showRenderTimes: ko.observable(false)
}; 
ko.applyBindings(viewModel);

我刚刚进行了一项更改 - 添加了

<input type="text" data-bind="value: $data">

一切都很好显示。但是值更改后文本不会更新。似乎绑定不起作用。我在实际项目中也遇到了同样的问题。这让我很困惑。怎么了? 提前致谢。

【问题讨论】:

    标签: knockout.js binding


    【解决方案1】:

    你举的例子不是特别适合做双向绑定工作,但我们还是试试吧。请注意,children 是可观察的 array(因此会注意到添加/删除),但其中的项目是纯字符串,不是可观察的。要使双向绑定起作用,您需要它。

    此外,“孩子”只是一个普通字符串,使事情变得更加复杂。

    我建议稍微编辑一下示例,以确保子级映射到 new Person(...) 实例并使其 name 属性为 ko.observable(...)。然后addChild 函数还应该创建new Person(...) 实例。

    看这个例子:

    // Define a "Person" class that tracks its own name and children, and has a method to add a new child
    var Person = function(name, children) {
        this.name = ko.observable(name);
        this.children = ko.observableArray(children.map(c => new Person(c, []))); 
        this.addChild = function() {
            this.children.push(new Person("New child", []));
        }.bind(this);
    } 
    // The view model is an abstract description of the state of the UI, but without any knowledge of the UI technology (HTML)
    var viewModel = {
        people: [
            new Person("Annabelle", ["Arnie", "Anders", "Apple"]),
            new Person("Bertie", ["Boutros-Boutros", "Brianna", "Barbie", "Bee-bop"]),
            new Person("Charles", ["Cayenne", "Cleopatra"])
        ],
        showRenderTimes: ko.observable(false)
    }; 
    ko.applyBindings(viewModel);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
    
    <h2>People</h2>
    <ul data-bind="foreach: people">
        <li>
            <div>          
                <span data-bind="text: name"> </span> has <span data-bind='text: children().length'>&nbsp;</span> children:
                <a href='#' data-bind='click: addChild '>Add child</a>
                <span class='renderTime' data-bind='visible: $root.showRenderTimes'>
                    (person rendered at <span data-bind='text: new Date().getSeconds()' > </span>)
                </span>
            </div>
            <ul data-bind="foreach: children">
                <li>
                  <input type="text" data-bind="value: name">
                    <span data-bind="text: name"> </span>
                    <span class='renderTime' data-bind='visible: $root.showRenderTimes'>
                        (child rendered at <span data-bind='text: new Date().getSeconds()' > </span>)
                    </span>
                </li>
            </ul>
        </li>
    </ul>
    <label><input data-bind='checked: showRenderTimes' type='checkbox' /> Show render times</label>

    【讨论】:

    • 非常感谢您的帮助。它现在对我有用。但是关于这个话题又出现了一个问题。在推送到子数组时,您会创建 Person 的新对象。但是如果 Person 类没有描述 children 数组中的对象会怎样呢?在这种情况下,我应该创建另一个类构造函数,即 Child 并将 new Child (..) 推送到 children 数组吗?提前致谢。
    • 这是一个设计问题,而不是技术问题(据我了解)。由你决定。 (如果实例具有不同的属性,我只会创建一个单独的类,通常情况并非如此:某人的孩子可以有他/她自己的孩子,因此 IMO 通常是一个人......)
    • 我明白了。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多