Magento 2如何应用KnockoutJS绑定


19

根据对KnockoutJS文档的粗略阅读,初始化一个非常基本的Knockout视图如下所示

// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
    this.firstName = "Bert";
    this.lastName = "Bertington";
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

即-您创建一个旨在用作对象构造函数的javascript函数,实例化该对象,然后将该对象传递到ko.applyBindings全局剔除对象(ko)的方法中

但是,在Magento 2中,如果您使用Grid UI加载后端页面,则Magento将初始化js/core/app.jsRequireJS模块

/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
define([
    './renderer/types',
    './renderer/layout',
    'Magento_Ui/js/lib/ko/initialize'
], function (types, layout) {
    'use strict';

    return function (data) {
        types.set(data.types);
        layout(data.components);
    };
});

该模块反过来加载该Magento_Ui/js/lib/ko/initialize模块,该模块似乎初始化了Magento对KnockoutJS的使用。但是,如果您查看初始化模块的来源。

define([
    'ko',
    './template/engine',
    'knockoutjs/knockout-repeat',
    'knockoutjs/knockout-fast-foreach',
    'knockoutjs/knockout-es5',
    './bind/scope',
    './bind/staticChecked',
    './bind/datepicker',
    './bind/outer_click',
    './bind/keyboard',
    './bind/optgroup',
    './bind/fadeVisible',
    './bind/mage-init',
    './bind/after-render',
    './bind/i18n',
    './bind/collapsible',
    './bind/autoselect',
    './extender/observable_array',
    './extender/bound-nodes'
], function (ko, templateEngine) {
    'use strict';

    ko.setTemplateEngine(templateEngine);
    ko.applyBindings();
});

你看Magento的所谓的ko.applyBindings();对象,而不视图对象。这没有任何意义,我不确定这是否是我对淘汰赛的有限了解,还是Magento在这里做自定义/奇怪的事情。

这是Magento实际应用Knockout绑定的地方吗?还是发生在其他地方?还是Magento做一些棘手的事情来拦截Knockout代码并在其他地方处理它?

Answers:


38

Magento_Ui/js/lib/ko/initialize实际上,该库是Magento初始化其Knockout实例的地方。Magento 应用绑定时不会分配ViewModel。

缺少的键是名为的自定义KnockoutJS绑定scope

当Magento的Knockout实例遇到这样的scope:绑定时

<li class="greet welcome" data-bind="scope: 'customer'">
    <span data-bind="text: customer().fullname ? $t('Welcome, %1!').replace('%1', customer().fullname) : 'Default welcome msg!'"></span>
</li>

它采用该绑定的值(名为customer),并使用它为加载和应用ViewModel用于内部节点uiRegistry。您可以使用一些简单的KnockoutJS pre调试来调试绑定到特定范围的数据

<div data-bind="scope: 'someScope'">
    <pre data-bind="text: ko.toJSON($data, null, 2)"></pre>            
</div>

uiRegistry是一个简单的字典等目的,在实现Magento_Ui/js/lib/registry/registryRequireJS模块。

vendor/magento/module-ui/view/base/requirejs-config.js
17:            uiRegistry:     'Magento_Ui/js/lib/registry/registry',

对象通过如下所示的javascript比特放入注册表中

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "customer": {
                    "component": "Magento_Customer/js/view/customer",
                    "extra_data_1":"some_value",
                    "more_extra":"some_other_value",
                }
            }
        }
    }
}
</script>

Magento_Ui/js/core/app模块中的程序将检查components传入对象的键,对于每个子对象,

  1. RequireJScomponent键(Magento_Customer/js/view/customer)中获取指定模块返回的对象

  2. 使用该对象实例化一个新的 javascript对象(请参见下文)

  3. 将任何额外的数据键分配给同一对象

  4. uiRegistry使用原始对象的键(customer上方)将该对象添加到中

如果您不确定x-magento-init脚本的工作方式,那么我在这里写了一篇有关它的文章

在此答案中,对此app.js过程进行更深入的检查。

范围绑定的实现在这里定义

vendor/magento//module-ui/view/base/web/js/lib/ko/bind/scope.js

艾伦,这是一个很好的答案!感谢您的信息。关于项目符号点3,它将如何向新实例化的对象添加额外的数据密钥。会是房地产还是其他?
Timik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.