Kode PHP untuk komponen UI membuat inisialisasi javascript yang terlihat seperti ini
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app":{
"types":{...},
"components":{...},
}
}
}
</script>
Sedikit kode di halaman ini berarti Magento akan memanggil Magento_Ui/js/core/appmodul RequireJS untuk mengambil panggilan balik, dan kemudian memanggil panggilan balik yang lewat di {types:..., components:...}objek JSON sebagai argumen (di databawah)
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
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);
};
});
Objek data berisi semua data yang diperlukan untuk membuat komponen UI, serta konfigurasi yang menghubungkan string tertentu dengan modul Magento RequireJS tertentu. Pemetaan itu terjadi di modul typesdan layoutRequireJS. Aplikasi ini juga memuat Magento_Ui/js/lib/ko/initializeperpustakaan RequireJS. The initializeModul kicks off integrasi KnockoutJS Magento.
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js
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();
});
Setiap bind/...modul RequireJS individu menyiapkan satu ikatan khusus untuk Knockout.
The extender/...RequireJS modul menambahkan beberapa metode pembantu untuk KnockoutJS benda asli.
Magento juga memperluas fungsi mesin templat javascript Knockout di ./template/enginemodul RequireJS.
Akhirnya, Magento memanggil applyBindings()objek KnockoutJS. Ini biasanya di mana program Knockout akan mengikat model tampilan ke halaman HTML - namun, Magento panggilan applyBindings tanpa model tampilan. Ini berarti Knockout akan mulai memproses halaman sebagai tampilan, tetapi tanpa data terikat.
Dalam pengaturan Knockout stok, ini akan sedikit konyol. Namun, karena binding Knockout yang disebutkan sebelumnya, ada banyak peluang bagi Knockout untuk melakukan sesuatu.
Kami tertarik dengan pengikatan lingkup . Anda dapat melihat bahwa dalam HTML ini, juga ditampilkan oleh sistem Komponen PHP UI.
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
<div class="spinner">
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<!-- ko template: getTemplate() --><!-- /ko -->
<script type="text/x-magento-init">
</script>
</div>
Secara khusus, data-bind="scope: 'customer_listing.customer_listing'">atribut. Saat Magento dimulai applyBindings, Knockout akan melihat scopepengikatan khusus ini , dan menjalankan ./bind/scopemodul RequireJS. Kemampuan untuk menerapkan pengikatan khusus adalah KnockoutJS murni. The pelaksanaan lingkup mengikat adalah sesuatu Magento Inc telah dilakukan.
Implementasi dari pengikatan lingkup adalah di
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js
Bit penting dalam file ini ada di sini
var component = valueAccessor(),
apply = applyComponents.bind(this, el, bindingContext);
if (typeof component === 'string') {
registry.get(component, apply);
} else if (typeof component === 'function') {
component(apply);
}
Tanpa terlalu detail, registry.getmetode akan mengeluarkan objek yang sudah dibuat menggunakan string dalam componentvariabel sebagai pengidentifikasi, dan meneruskannya ke applyComponentsmetode sebagai parameter ketiga. Pengidentifikasi string adalah nilai scope:(di customer_listing.customer_listingatas)
Di applyComponents
function applyComponents(el, bindingContext, component) {
component = bindingContext.createChildContext(component);
ko.utils.extend(component, {
$t: i18n
});
ko.utils.arrayForEach(el.childNodes, ko.cleanNode);
ko.applyBindingsToDescendants(component, el);
}
panggilan untuk createChildContextakan membuat apa yang pada dasarnya adalah objek viewModel baru berdasarkan objek komponen yang sudah dipakai sebelumnya, dan kemudian menerapkannya ke semua elemen turunan dari dokumen asli divyang digunakan data-bind=scope:.
Jadi, apa objek komponen yang sudah instantiated ? Ingat panggilan untuk layoutkembali app.js?
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
layout(data.components);
The layoutFungsi / modul akan turun ke disahkan pada data.components(sekali lagi, data ini berasal dari objek berlalu dalam melalui text/x-magento-init). Untuk setiap objek yang ditemukannya, ia akan mencari configobjek, dan dalam objek konfigurasi itu akan mencari componentkunci. Jika ia menemukan kunci komponen, itu akan
Gunakan RequireJSuntuk mengembalikan instance modul - seolah-olah modul dipanggil dalam requirejs/ definedependensi.
Sebut instance modul sebagai konstruktor javascript
Simpan objek yang dihasilkan dalam registryobjek / modul
Jadi, itu banyak yang bisa diterima. Berikut ulasan singkatnya, gunakan
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
<div class="spinner">
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<!-- ko template: getTemplate() --><!-- /ko -->
<script type="text/x-magento-init">
</script>
</div>
sebagai titik awal. The scopenilainya customer_listing.customer_listing.
Jika kita melihat objek JSON dari text/x-magento-initinisialisasi
{
"*": {
"Magento_Ui/js/core/app": {
/* snip */
"components": {
"customer_listing": {
"children": {
"customer_listing": {
"type": "customer_listing",
"name": "customer_listing",
"children": /* snip */
"config": {
"component": "uiComponent"
}
},
/* snip */
}
}
}
}
}
}
Kita melihat components.customer_listing.customer_listingobjek memiliki configobjek, dan objek konfigurasi tersebut memiliki componentobjek yang diatur ke uiComponent. The uiComponentstring adalah modul RequireJS. Bahkan, ini merupakan alias RequireJS yang sesuai dengan Magento_Ui/js/lib/core/collectionmodul.
vendor/magento/module-ui/view/base/requirejs-config.js
14: uiComponent: 'Magento_Ui/js/lib/core/collection',
Di layout.js, Magento telah menjalankan kode yang setara dengan yang berikut ini.
//The actual code is a bit more complicated because it
//involves jQuery's promises. This is already a complicated
//enough explanation without heading down that path
require(['Magento_Ui/js/lib/core/collection'], function (collection) {
object = new collection({/*data from x-magento-init*/})
}
Untuk yang benar-benar penasaran, jika Anda melihat dalam model koleksi dan mengikuti jalur eksekusi, Anda akan menemukan bahwa itu collectionadalah objek javascript yang telah ditingkatkan baik oleh lib/core/element/elementmodul dan lib/core/classmodul. Meneliti penyesuaian ini berada di luar cakupan jawaban ini.
Setelah dipakai, layout.jssimpan ini objectdi registri. Ini berarti ketika Knockout mulai memproses binding dan menemukan custom scopebinding
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<!-- snip -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!-- snip -->
</div>
Magento akan mengambil objek ini kembali dari registri, dan mengikatnya sebagai model tampilan untuk hal-hal di dalamnya div. Dengan kata lain, getTemplatemetode yang dipanggil saat Knockout memanggil tagless binding ( <!-- ko template: getTemplate() --><!-- /ko -->) adalah getTemplatemetode pada new collectionobjek.