In che modo Magento 2 applica gli attacchi KnockoutJS


19

Per una lettura molto superficiale della documentazione di KnockoutJS, l'inizializzazione di una vista Knockout molto semplice è simile alla seguente

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

vale a dire - si crea una funzione javascript destinata ad essere utilizzata come costruttore di oggetti, creare un'istanza di un oggetto da esso e quindi passare quell'oggetto nel ko.applyBindingsmetodo dell'oggetto knockout globale ( ko)

Tuttavia, in Magento 2, se carichi una pagina di back-end con un'interfaccia utente a griglia, Magento inizializzerà il js/core/app.jsmodulo 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);
    };
});

Questo modulo, a sua volta, carica il Magento_Ui/js/lib/ko/initializemodulo, che sembra inizializzare l'utilizzo di KnockoutJS da parte di Magento. Tuttavia, se si osserva l'origine del modulo di inizializzazione.

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

Vedi Magento è chiamato l' ko.applyBindings();oggetto senza un oggetto vista . Questo non ha alcun senso, e non sono sicuro che sia la mia comprensione limitata di Knockout, o Magento che fa qualcosa di personalizzato / strano qui.

È qui che Magento applica effettivamente i vincoli Knockout? O succede altrove? Oppure Magento sta facendo qualcosa di complicato per intercettare il codice Knockout ed elaborarlo altrove?

Risposte:


38

La Magento_Ui/js/lib/ko/initializelibreria è, infatti, dove Magento inizializza la sua istanza Knockout. Magento non assegna un ViewModel quando applica i bind.

La chiave mancante qui è l' associazione KnockoutJS personalizzata denominata scope.

Quando l'istanza Knockout di Magento incontra un'associazione scope:come questa

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

Prende il valore di quell'associazione (denominata customer) e lo utilizza per caricare e applicare un ViewModel per i nodi interni da uiRegistry. Puoi eseguire il debug dei dati associati a un determinato ambito con un semplice predebug di KnockoutJS

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

Il uiRegistryè un semplice dizionario come oggetto, implementato nel Magento_Ui/js/lib/registry/registrymodulo di RequireJS.

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

Gli oggetti vengono inseriti nel registro tramite i bit di JavaScript che assomigliano a questo

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

Il programma nel Magento_Ui/js/core/appmodulo esaminerà la componentschiave dell'oggetto passato e per ogni oggetto secondario lo farà

  1. Recupera l'oggetto restituito dal RequireJSmodulo specificato dalla componentchiave ( Magento_Customer/js/view/customer)

  2. Usa quell'oggetto per creare un'istanza di un nuovo oggetto javascript (vedi sotto)

  3. Assegna eventuali chiavi di dati extra allo stesso oggetto

  4. Aggiungi lo stesso oggetto al uiRegistrycon la chiave dell'oggetto originale ( customersopra)

Se non sei sicuro di come funzioni lo x-magento-initscript, ho scritto un articolo al riguardo qui .

In questa risposta c'è un esame più approfondito del app.jsprocesso .

L'implementazione dell'associazione di ambito è definita qui

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

Alan è un'ottima risposta! Grazie per l'informazione. Per quanto riguarda il punto 3 del proiettile, come aggiungere chiavi dati aggiuntive all'oggetto appena istanziato. Saranno proprietà o qualcos'altro?
Timik
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.