W jaki sposób Magento 2 stosuje wiązania KnockoutJS

19

Po bardzo pobieżnym przeczytaniu dokumentacji KnockoutJS, inicjalizacja bardzo podstawowego widoku Knockout wygląda następująco:

// 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());

tj. - tworzysz funkcję javascript przeznaczoną do użycia jako konstruktor obiektów, tworzysz z niej instancję obiektu, a następnie przekazujesz ten obiekt do ko.applyBindingsmetody globalnego obiektu knockout ( ko)

Jednak w Magento 2, jeśli załadujesz stronę zaplecza za pomocą interfejsu Grid, Magento zainicjuje js/core/app.jsmoduł RequireJS

/**
 * 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);
    };
});

Ten moduł z kolei ładuje Magento_Ui/js/lib/ko/initializemoduł, który wydaje się inicjować użycie KnockoutJS przez Magento. Jeśli jednak spojrzysz na źródło modułu inicjalizacji.

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();
});

Widzisz, jak Magento nazywa się ko.applyBindings();obiektem bez obiektu widoku . To nie ma sensu i nie jestem pewien, czy to moje ograniczone rozumienie Knockout, czy Magento robi tutaj coś niestandardowego / dziwnego.

Czy to właśnie tam Magento stosuje wiązania Knockout? A może dzieje się to gdzie indziej? A może Magento robi coś trudnego do przechwycenia kodu Knockout i przetworzenia go w innym miejscu?

Alan Storm
źródło

Odpowiedzi:

38

W Magento_Ui/js/lib/ko/initializebibliotece rzeczywiście Magento inicjuje instancję Knockout. Magento nie przypisuje ViewModel, gdy stosuje wiązania.

Brakującym kluczem tutaj jest niestandardowe powiązanie KnockoutJS o nazwie scope.

Gdy instancja Knockouta Magento napotyka takie scope:powiązanie

<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>

Pobiera wartość tego wiązania (o nazwie customer) i używa go do załadowania i zastosowania ViewModel dla wewnętrznych węzłów z uiRegistry. Możesz debugować dane powiązane dla określonego zakresu za pomocą prostego predebugowania KnockoutJS

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

uiRegistryJest prosty słownik jak przedmiot, realizowany w Magento_Ui/js/lib/registry/registrymodule RequireJS.

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

Obiekty są umieszczane w rejestrze za pomocą bitów javascript, które wyglądają tak

<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>

Program w Magento_Ui/js/core/appmodule zbada componentsklucz przekazanego obiektu i dla każdego podobiektu zrobi to

  1. Pobierz obiekt zwrócony przez określony RequireJSmoduł z componentkey ( Magento_Customer/js/view/customer)

  2. Użyj tego obiektu do utworzenia nowego obiektu javascript (patrz poniżej)

  3. Przypisz dodatkowe klucze danych do tego samego obiektu

  4. Dodaj ten sam obiekt do uiRegistryklucza oryginalnego obiektu ( customerpowyżej)

Jeśli nie jesteś pewien, jak x-magento-initdziała skrypt, napisałem o nim artykuł .

Jest bardziej dogłębne badanie app.jsprocesu nad tą odpowiedzią .

W tym miejscu zdefiniowano implementację wiązania zakresu

vendor/magento//module-ui/view/base/web/js/lib/ko/bind/scope.js
Alan Storm
źródło
Alan, to świetna odpowiedź! Dziękuję za informację. Jeśli chodzi o punkt 3, w jaki sposób doda on dodatkowe klucze danych do nowo utworzonego obiektu. Czy będą to właściwości czy coś innego?
Timik