Knockoutjs:从子组件调用父组件的功能

时间:2015-07-09 06:43:23

标签: javascript knockout.js knockout-components

问题: 我正在尝试构建一个小部件仪表板。每个小部件的标题上都有一个删除按钮。单击此按钮时,相应的小部件必须消失。

我的设计方式: 我有两个淘汰赛组件。

  1. 我的,窗口小部件列表: VO将有一个observableArray的widget对象。
  2. 我的窗口小部件: VO将在小部件中显示详细信息。
  3. 注意:为简单起见,我只用数字替换widget对象。

    
    
    ko.components.register('my-widget-list', {       
        viewModel : function(params) {
            var self = this;
            self.values = ko.observableArray([10,20,30,40,50]);
    
            self.deleteWidget = function(obj)
            {
                self.values.remove(obj);
            }
        },
        template: {element: 'my-widget-list-template'}
    });
    
    ko.components.register('my-widget', {
        viewModel : function(params) {        
            var self = this;        
            self.value = params.value;                        
        },
        template: {element: 'my-widget-template'}
    });
    
    ko.applyBindings({}); 
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <my-widget-list></my-widget-list>
    
    <script id="my-widget-list-template" type="text/html">
        <div data-bind="foreach:values">
            <my-widget params="value: $data"></my-widget><br>
        </div>
    </script>
    
    <script id="my-widget-template" type="text/html">
        <span data-bind="text: value"></span>
        <button data-bind="click: $parent.deleteWidget">Delete</button>
    </script>
    &#13;
    &#13;
    &#13;

    现在,我想在点击按钮时调用my-widget-list的{​​{1}}功能。

    我想过

    • 将父视图模型引用传递给子项
    • 将子组件的params属性中的父函数作为回调传递

    但我希望从专家那里知道实现这一目标的最佳途径。

    JsFiddle Link

    提前致谢

1 个答案:

答案 0 :(得分:8)

您可以将父项作为参数传递给子项:

&#13;
&#13;
ko.components.register('my-widget-list', {       
    viewModel : function(params) {
        var self = this;
        self.values = ko.observableArray([10,20,30,40,50]);

        self.deleteWidget = function(obj) {
            self.values.remove(obj);
        }
    },
    template: {element: 'my-widget-list-template'}
});

ko.components.register('my-widget', {
    viewModel : function(params) {        
        var self = this;        

        self.value = params.value;
        self.remove = function () {
            params.parent.deleteWidget(self.value);
        };
    },
    template: {element: 'my-widget-template'}
});

ko.applyBindings({});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<my-widget-list></my-widget-list>

<script id="my-widget-list-template" type="text/html">
    <div data-bind="foreach:values">
        <my-widget params="value: $data, parent: $parent"></my-widget><br>
    </div>
</script>

<script id="my-widget-template" type="text/html">
    <span data-bind="text: value"></span>
    <button data-bind="click: remove">Delete</button>
</script>
&#13;
&#13;
&#13;

但我不确定这是不是一个好主意,因为它不必要地将孩子与父母联系起来。

我建议实施&#34;删除&#34;父节点中的按钮,即在<my-widget-list>中,这样小部件可以在没有小部件列表的情况下存在(或者以不同结构的方式存在),而小部件列表控制其子节点。

比较窗口管理器:它们以相同的方式工作。窗口管理器绘制框架和最小化/最大化/关闭按钮,而窗口内容由相应的子进程绘制。这种逻辑在你的场景中也是有意义的。

在父级中使用removeWidget控件的替代实现:

&#13;
&#13;
ko.components.register('my-widget-list', {
    viewModel : function(params) {
        var self = this;

        self.values = ko.observableArray([10,20,30,40,50]);

        self.deleteWidget = function(obj) {
            self.values.remove(obj);
        }
    },
    template: {element: 'my-widget-list-template'}
});

ko.components.register('my-widget', {
    viewModel : function(params) {
        var self = this;

        self.value = params.value;
    },
    template: {element: 'my-widget-template'}
});

ko.applyBindings({});
&#13;
.widget-container {
  position: relative;
  display: inline-block;
  padding: 10px 5px 5px 5px;
  margin: 0 5px 5px 0;
  border: 1px solid silver;
  border-radius: 2px;
  min-width: 40px;
}
.widget-buttons {
  position: absolute;
  top: 2px;
  right: 2px;
}
.widget-buttons > button {
  font-size: 2px;
  padding: 0;
  height: 15px;
  width: 15px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<my-widget-list></my-widget-list>

<script id="my-widget-list-template" type="text/html">
    <div class="widget-list" data-bind="foreach:values">
        <div class="widget-container">
            <div class="widget-buttons">
                <button data-bind="click: $parent.deleteWidget">X</button>
            </div>
            <my-widget params="value: $data"></my-widget>
        </div>
    </div>
</script>

<script id="my-widget-template" type="text/html">
    <div class="widget">
        <span data-bind="text: value"></span>
    </div>
</script>
&#13;
&#13;
&#13;