Comment Magento 2 applique-t-il les liaisons KnockoutJS


19

Selon une lecture très rapide de la documentation KnockoutJS, l'initialisation d'une vue Knockout très basique ressemble à ce qui suit

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

c'est-à-dire que vous créez une fonction javascript destinée à être utilisée comme constructeur d'objet, instanciez un objet à partir de celui-ci, puis passez cet objet dans la ko.applyBindingsméthode de l'objet knockout global ( ko)

Cependant, dans Magento 2, si vous chargez une page principale avec une interface utilisateur de grille, Magento initialisera le js/core/app.jsmodule 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);
    };
});

Ce module, à son tour, charge le Magento_Ui/js/lib/ko/initializemodule, qui semble initialiser l'utilisation de KnockoutJS par Magento. Cependant, si vous regardez la source du module d'initialisation.

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

Vous voyez Magento appelé l' ko.applyBindings();objet sans objet de vue . Cela n'a aucun sens, et je ne sais pas si c'est ma compréhension limitée de Knockout, ou Magento fait quelque chose de personnalisé / étrange ici.

Est-ce là que Magento applique réellement les liaisons Knockout? Ou cela se produit-il ailleurs? Ou est-ce que Magento fait quelque chose de délicat pour intercepter le code Knockout et le traiter ailleurs?

Réponses:


38

La Magento_Ui/js/lib/ko/initializebibliothèque est, en effet, où Magento initialise son instance Knockout. Magento n'attribue pas de ViewModel lorsqu'il applique des liaisons.

La clé manquante ici est la liaison KnockoutJS personnalisée nommée scope.

Lorsque l'instance Knockout de Magento rencontre une scope:liaison comme celle-ci

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

Il prend la valeur de cette liaison (nommée customer) et l'utilise pour charger et appliquer un ViewModel pour les nœuds internes à partir du uiRegistry. Vous pouvez déboguer les données liées pour une portée particulière avec un predébogage simple KnockoutJS

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

Il uiRegistrys'agit d'un simple objet de type dictionnaire, implémenté dans le Magento_Ui/js/lib/registry/registrymodule RequireJS.

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

Les objets sont placés dans le registre via les bits de javascript qui ressemblent à ceci

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

Le programme du Magento_Ui/js/core/appmodule examinera la componentsclé de l'objet transmis et, pour chaque sous-objet,

  1. Récupère l'objet renvoyé par le RequireJSmodule spécifié à partir de la componentclé ( Magento_Customer/js/view/customer)

  2. Utilisez cet objet pour instancier un nouvel objet javascript (voir ci-dessous)

  3. Attribuer des clés de données supplémentaires à ce même objet

  4. Ajoutez ce même objet au uiRegistryavec la clé de l'objet d'origine ( customerci-dessus)

Si vous ne savez pas comment fonctionne le x-magento-initscript, j'ai écrit un article à ce sujet ici .

Il y a un examen plus approfondi du app.jsprocessus dans cette réponse .

L'implémentation de la liaison de portée est définie ici

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

Alan, c'est une excellente réponse! Merci pour l'information. En ce qui concerne le point 3, comment ajoutera-t-il des clés de données supplémentaires à l'objet nouvellement instancié. Sera-ce des propriétés ou autre chose?
Timik
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.