【问题标题】:KnockoutJS: calling function on a childKnockoutJS:在孩子身上调用函数
【发布时间】:2014-05-06 07:40:39
【问题描述】:

这里是脚本:jsFiddle(内联脚本见下文)。

P (Page) 是 S (Section) 对象的容器,SF (Field) 对象的容器。当您单击“添加部分”时,您将获得一个新部分。同样,当单击“将字段添加到部分”时,您将在所选部分 (currentSec) 中获得一个新字段。

我不知道 KO 是否有直接在 Section 对象上调用 addField() 函数的语法——这就是我要找的。显然,“添加字段”按钮的当前数据绑定当前不正确。

我知道我可以将addField() 移动到 Page 对象并让它使用currentSec 来做它的事情,但我想知道我是否可以保持我的结构并仍然获得相同的结果。我非常喜欢坚持我的 OOP 最佳实践。

HTML:

<div data-bind="foreach: secs">
    <section class="section" data-bind="click: $parent.currentSec, attr: {id: id}">
        <div data-bind="text: $data.id"/>
        <ul data-bind="foreach: $data.fields">
            <li data-bind="attr: {id: id}">New Field</li>
        </ul>
    </section>
</div>
<button data-bind="click: addSection">Add Section</button>

<div data-bind="with: currentSec">
    <button data-bind="click: addField">Add Field to Section</button>
</div>

JS:

function P() {
    this.id = 'pageId';
    this.secs = ko.observableArray();
    this.currentSec = ko.observable();
}
P.prototype.addSection = function() {
    this.secs.push(new S("section" + this.secs().length));
}

function S(sid) {
    this.id = sid;
    this.fields = ko.observableArray();
    this.currentField = ko.observable();
}
S.prototype.addField = function() {
    this.fields.push(new F("field" + this.fields().length));
}

function F(fid) {
    this.id = fid;
}

ko.applyBindings(new P());

【问题讨论】:

    标签: knockout.js


    【解决方案1】:

    是的,这是可能的。检查this fiddle。它基本上运行在这个:

    <!-- ko with: currentSec -->
    <button data-bind="click: addField">Add Field to Section</button>
    <!-- /ko -->
    

    它为当前部分的按钮设置一个context using the with binding,使click绑定正常工作。

    在用户体验方面,尽管让“添加字段”按钮出现在部分本身的某处可能更有意义。无论如何,在该部分中,您都有正确的上下文。


    我确实需要对您的代码进行一些调整以使其正常运行(我不确定其中有多少是真正需要,但重构这些项目帮助我得到了提到的小提琴):

    • 我倾向于将this 存储在构造函数内部的变量self 中,以避免this 在内部函数(例如addSection)内部出现问题。
    • 有些相关,我将函数移到构造函数本身内部,因此它们可以通过构造函数闭包访问self
    • 我添加了一些“活动”css(我花了一点时间才发现单击某个部分允许我将其“选择”为当前部分。
    • 我已经做到了,addSection 将当前部分设置为新部分(但这当然是可选的)。
    • div 是自动关闭的,但这往往会引起麻烦;所以我添加了一个&lt;/div&gt; 结束标记。

    对于手头的问题,这些都不是太重要。为了完整起见,这是完整的工作重现:

    <div id="page0" data-bind="foreach: secs">
        <section class="section" data-bind="click: $parent.currentSec, attr: {id: id}, css: { active: $parent.currentSec() == $data }">
            <div data-bind="text: $parent.id"></div>
            <ul class="connected" data-bind="foreach: fields">
                <li data-bind="attr: {id: id}, click: $parent.currentField">New Field</li>
            </ul>
        </section>
    </div>
    <button data-bind="click: addSection">Add Section</button>
    <button data-bind="click: currentSec().addField">Add Field to Section</button>
    

    有了这个 JS:

    function P() {
        var self = this;
        self.id = 'pageId';
        self.secs = ko.observableArray();
        self.currentSec = ko.observable();
        self.addSection = function() {
            var newSection = new S("section" + self.secs().length);
            self.currentSec(newSection);
            self.secs.push(newSection);
        }
    }
    
    function S(sid) {
        var self = this;
        self.id = sid;
        self.fields = ko.observableArray();
        self.currentField = ko.observable();
        self.addField = function() {
            self.fields.push(new F("field" + self.fields().length));
        };
    }
    
    function F(fid) {
        var self = this;
        self.id = fid;
    }
    
    var pvm = new P();
    ko.applyBindings(pvm);
    

    【讨论】:

    • 这太疯狂了,KO 如何将 cmets 解释为虚拟 DOM 元素。在阅读了您的回复后,我对文档进行了更多挖掘,并找到了解释这一点的部分。有时您直到最终不得不使用它时才理解某些东西!但是,你知道为什么我更新的脚本不起作用吗?我正在使用
    • @user1936026 您的代码在&lt;div data-bind="with: currentSec"&gt; jsfiddle.net/yQb5q 上运行良好,您刚刚再次自我整理您的div:&lt;div data-bind="text: $data.id"&gt; &lt;/div&gt;
    • 嗯,看起来你是对的。我不明白为什么自动关闭 div 会导致 addField() 不起作用。顺便谢谢!
    • 参见例如this 了解更多信息。简短版本:在 html4 中,自关闭 div 无效。在 xhtml 中它是,但只有当你有完全正确的 mime 类型 时才有效(只是 doctype 的东西不会削减它)。在 html5 中 &lt;div /&gt; 等于 &lt;div&gt;,我不确定这在内部浏览器中意味着什么,特别是对于 KO,但我可以想象它会给 text 绑定之类的东西带来麻烦,它可能会尝试访问内部文本节点没有空元素。 (唯一可以确定的方法是深入研究源代码,我猜......)
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签