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/app
modul RequireJS untuk mengambil panggilan balik, dan kemudian memanggil panggilan balik yang lewat di {types:..., components:...}
objek JSON sebagai argumen (di data
bawah)
#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 types
dan layout
RequireJS. Aplikasi ini juga memuat Magento_Ui/js/lib/ko/initialize
perpustakaan RequireJS. The initialize
Modul 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/engine
modul 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 scope
pengikatan khusus ini , dan menjalankan ./bind/scope
modul 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.get
metode akan mengeluarkan objek yang sudah dibuat menggunakan string dalam component
variabel sebagai pengidentifikasi, dan meneruskannya ke applyComponents
metode sebagai parameter ketiga. Pengidentifikasi string adalah nilai scope:
(di customer_listing.customer_listing
atas)
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 createChildContext
akan 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 div
yang digunakan data-bind=scope:
.
Jadi, apa objek komponen yang sudah instantiated ? Ingat panggilan untuk layout
kembali app.js
?
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
layout(data.components);
The layout
Fungsi / 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 config
objek, dan dalam objek konfigurasi itu akan mencari component
kunci. Jika ia menemukan kunci komponen, itu akan
Gunakan RequireJS
untuk mengembalikan instance modul - seolah-olah modul dipanggil dalam requirejs
/ define
dependensi.
Sebut instance modul sebagai konstruktor javascript
Simpan objek yang dihasilkan dalam registry
objek / 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 scope
nilainya customer_listing.customer_listing
.
Jika kita melihat objek JSON dari text/x-magento-init
inisialisasi
{
"*": {
"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_listing
objek memiliki config
objek, dan objek konfigurasi tersebut memiliki component
objek yang diatur ke uiComponent
. The uiComponent
string adalah modul RequireJS. Bahkan, ini merupakan alias RequireJS yang sesuai dengan Magento_Ui/js/lib/core/collection
modul.
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 collection
adalah objek javascript yang telah ditingkatkan baik oleh lib/core/element/element
modul dan lib/core/class
modul. Meneliti penyesuaian ini berada di luar cakupan jawaban ini.
Setelah dipakai, layout.js
simpan ini object
di registri. Ini berarti ketika Knockout mulai memproses binding dan menemukan custom scope
binding
<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, getTemplate
metode yang dipanggil saat Knockout memanggil tagless binding ( <!-- ko template: getTemplate() --><!-- /ko -->
) adalah getTemplate
metode pada new collection
objek.
<uiComponents/>
dari tata letak sistem XML. Manfaat yang mereka dapatkan adalah kemampuan untuk menukar model tampilan pada halaman yang sama untuk serangkaian tag yang berbeda.Ikatan untuk salah satu templat JS KO terjadi di file .xml modul. Menggunakan modul Checkout sebagai contoh Anda dapat menemukan konfigurasi untuk
content
template divendor/magento/module-checkout/view/frontend/layout/default.xml
Dalam file ini Anda dapat melihat bahwa kelas blok memiliki node yang mendefinisikan "jsLayout" dan memanggil
<item name="minicart_content" xsi:type="array">
. Ini sedikit dari logika bulat, tetapi jika Anda berada di dalamvendor/magento/module-checkout/view/frontend/templates/cart/minicart.phtml
Anda akan melihat baris ini:Jadi data-mengikat mengarahkan mana untuk mencari template bersarang, dalam hal ini adalah
Magento_Checkout/js/view/minicart
darivendor/magento/module-checkout/view/frontend/web/js/view/minicart.js
logika (atau MV di KO Model-View-View sistem Model) dan Anda memilikiMagento_Checkout/minicart/content
(atau V di KO Model-View-View Model sistem) untuk panggilan templat. Jadi templat yang ditarik di tempat ini adalahvendor/magento/module-checkout/view/frontend/web/template/minicart/content.html
.Sungguh tidak sulit untuk mencari tahu begitu Anda terbiasa mencari di .xml. Sebagian besar dari ini saya pelajari di sini jika Anda dapat melewati bahasa Inggris yang rusak. Tapi sejauh ini saya merasa integrasi Knockout adalah bagian M2 yang paling tidak terdokumentasi.
sumber
Saya cukup yakin metode JS global
getTemplate
yang Anda cari didefinisikan di bawahapp/code/Magento/Ui/view/base/web/js/lib/core/element/element.js
Anda dapat menemukannya di sini: https://github.com/magento/magento2/blob/4d71bb4780625dce23274c90e45788a72f345dd9/app/code/Magento/Ui/view/base /web/js/lib/core/element/element.js#L262Saat saya menggunakan ponsel, saya kesulitan menemukan bagaimana cara pengikatannya dilakukan.
sumber