Bagaimana Magento 2 Menerapkan KnockoutJS Bindings

19

Per bacaan dokumentasi KnockoutJS yang sangat sepintas lalu, menginisialisasi tampilan Knockout yang sangat mendasar terlihat seperti berikut ini

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

yaitu - Anda membuat fungsi javascript yang dimaksudkan untuk digunakan sebagai konstruktor objek, instantiate objek darinya, dan kemudian meneruskan objek itu ke ko.applyBindingsmetode objek global knockout ( ko)

Namun, di Magento 2, jika Anda memuat halaman backend dengan UI Grid, Magento akan menginisialisasi js/core/app.jsmodul 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);
    };
});

Modul ini, pada gilirannya, memuat Magento_Ui/js/lib/ko/initializemodul, yang muncul untuk menginisialisasi penggunaan KnockoutJS Magento. Namun, jika Anda melihat sumber modul inisialisasi.

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

Anda melihat Magento disebut ko.applyBindings();objek tanpa objek tampilan . Ini tidak masuk akal, dan saya tidak yakin apakah itu pemahaman saya yang terbatas tentang Knockout, atau Magento melakukan sesuatu yang aneh / aneh di sini.

Apakah ini di mana Magento benar-benar menerapkan ikatan Knockout? Atau apakah itu terjadi di tempat lain? Atau Magento melakukan sesuatu yang rumit untuk mencegat kode Knockout dan memprosesnya di tempat lain?

Alan Storm
sumber

Jawaban:

38

The Magento_Ui/js/lib/ko/initializeperpustakaan, memang, di mana Magento menginisialisasi contoh Knockout nya. Magento tidak menetapkan ViewModel saat menerapkan bindings.

Kunci yang hilang di sini adalah pengikatan KnockoutJS kustom bernama scope.

Ketika contoh Magento's Knockout menemukan scope:ikatan seperti ini

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

Dibutuhkan nilai yang mengikat (bernama customer), dan menggunakannya untuk memuat dan menerapkan Model View untuk node batin dari uiRegistry. Anda dapat men-debug data yang terikat untuk cakupan tertentu dengan beberapa predebug KnockoutJS sederhana

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

Ini uiRegistryadalah kamus sederhana seperti objek, diimplementasikan dalam Magento_Ui/js/lib/registry/registrymodul RequireJS.

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

Objek dimasukkan ke dalam registri melalui bit javascript yang terlihat seperti ini

<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 dalam Magento_Ui/js/core/appmodul akan memeriksa componentskunci dari objek yang dikirimkan, dan untuk setiap sub-objek akan

  1. Ambil objek yang dikembalikan oleh RequireJSmodul yang ditentukan dari componenttombol ( Magento_Customer/js/view/customer)

  2. Gunakan objek itu untuk membuat instance objek javascript baru (lihat di bawah)

  3. Tetapkan kunci data tambahan untuk objek yang sama

  4. Tambahkan objek yang sama ke uiRegistrydengan kunci dari objek asli (di customeratas)

Jika Anda tidak yakin bagaimana x-magento-initskrip bekerja, saya telah menulis artikel tentang itu di sini .

Ada lebih dalam pemeriksaan mendalam dari app.jsproses di dalam jawaban ini .

Implementasi pengikatan lingkup didefinisikan di sini

vendor/magento//module-ui/view/base/web/js/lib/ko/bind/scope.js
Alan Storm
sumber
Alan itu jawaban yang bagus! Terima kasih untuk informasinya. Mengenai poin 3, bagaimana cara menambahkan kunci data tambahan ke objek yang baru dipakai. Apakah itu properti atau sesuatu yang lain?
Timik