Bir UI bileşeninin PHP kodu şuna benzeyen bir javascript başlatması oluşturur
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app":{
"types":{...},
"components":{...},
}
}
}
</script>
Sayfadaki bu kod biti, Magento'nun Magento_Ui/js/core/appbir geri çağrı almak için RequireJS modülünü çağıracağı ve sonra {types:..., components:...}JSON nesnesine argüman olarak geçen bu geri çağrıyı çağıracağı anlamına gelir ( dataaşağıda)
#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);
};
});
Veri nesnesi , UI bileşenini oluşturmak için gereken tüm verilerin yanı sıra belirli dizeleri belirli Magento RequireJS modüllerine bağlayan bir yapılandırma içerir. Bu eşleme typesve layoutRequireJS modüllerinde gerçekleşir. Uygulama ayrıca Magento_Ui/js/lib/ko/initializeRequireJS kitaplığını yükler . initializeMagento'nın KnockoutJS entegrasyonu kapalı modül devreye giriyor.
/**
* 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();
});
Her bir bind/...RequireJS modülü , Nakavt için tek bir özel ciltleme kurar .
extender/...RequireJS modülleri yerli KnockoutJS nesnelere bazı yardımcı yöntemler ekleyin.
Magento, Knockout'un javascript şablon motorunun ./template/engineRequireJS modülündeki işlevselliğini de genişletir .
Sonunda Magento applyBindings(), KnockoutJS nesnesini çağırır . Bu genellikle bir Nakavt programının bir görünüm modelini HTML sayfasına bağlayacağı yerdir; ancak Magento, görünüm modeli applyBindings olmadan çağrı yapar . Bu, Nakavt'ın bir görünüm olarak sayfayı işlemeye başlayacağı, ancak veri bağlı olmadığı anlamına gelir.
Bir nakavt kurulumunda, bu biraz aptalca olurdu. Bununla birlikte, daha önce bahsedilen özel Nakavt ciltleri nedeniyle, Nakavt'ın bir şeyler yapması için birçok fırsat var.
Kapsam bağlayıcılığıyla ilgileniyoruz . Bunu, PHP UI Bileşen sistemi tarafından da oluşturulan bu HTML'de görebilirsiniz.
<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>
Özellikle, data-bind="scope: 'customer_listing.customer_listing'">öznitelik. Magento başladığında applyBindings, Nakavt bu özel scopebağlayıcıyı ./bind/scopegörür ve RequireJS modülünü çağırır . Özel bir bağlayıcı uygulama yeteneği saf KnockoutJS'dir. Uygulama bağlayıcı kapsamı şey Magento Inc. yapmış olduğunu.
Kapsam bağlayıcısının uygulanması
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js
Bu dosyadaki önemli kısım burada
var component = valueAccessor(),
apply = applyComponents.bind(this, el, bindingContext);
if (typeof component === 'string') {
registry.get(component, apply);
} else if (typeof component === 'function') {
component(apply);
}
Ayrıntılara fazla girilmeden, registry.getyöntem, componentdeğişken içindeki dizeyi tanımlayıcı olarak kullanarak önceden oluşturulmuş bir nesneyi çıkarır applyComponentsve üçüncü parametre olarak yönteme iletir. Dize tanımlayıcı değeri scope:( customer_listing.customer_listingyukarıda)
İçinde 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);
}
çağrısı createChildContext, esasen, halihazırda başlatılmış bileşen nesnesine dayanan yeni bir viewModel nesnesinin ne olduğunu oluşturur ve bunu divkullanılan orijinalin tüm alt öğelerine uygular data-bind=scope:.
Peki, zaten somutlaştırılmış bileşen nesnesi nedir? layoutGeri çağrıyı hatırlıyor app.jsmusunuz?
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
layout(data.components);
layoutİşlev / modül içinde geçirilen içine inecek data.components(yine, bu veriler ile geçirilen nesneden gelir text/x-magento-init). Bulduğu her nesne için bir confignesne arayacak ve bu yapılandırma nesnesinde bir componentanahtar arayacaktır . Bir bileşen anahtarı bulursa,
RequireJSBir modül örneğini döndürmek için kullanın - modül bir requirejs/ definebağımlılıkta çağrılmış gibi .
Bu modül örneğini javascript yapıcısı olarak adlandırın
Ortaya çıkan nesneyi registrynesne / modülde saklayın
Bu, alınması gereken çok şey. İşte hızlı bir inceleme, kullanarak
<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>
başlangıç noktası olarak. scopeDeğerdir customer_listing.customer_listing.
text/x-magento-initBaşlatmadan JSON nesnesine bakarsak
{
"*": {
"Magento_Ui/js/core/app": {
/* snip */
"components": {
"customer_listing": {
"children": {
"customer_listing": {
"type": "customer_listing",
"name": "customer_listing",
"children": /* snip */
"config": {
"component": "uiComponent"
}
},
/* snip */
}
}
}
}
}
}
components.customer_listing.customer_listingNesnenin bir confignesnesi olduğunu ve bu yapılandırma nesnesinin olarak componentayarlanmış bir nesnesi olduğunu görüyoruz uiComponent. uiComponentDize RequireJS modülüdür. Aslında, Magento_Ui/js/lib/core/collectionmodüle karşılık gelen bir RequireJS diğer adı .
vendor/magento/module-ui/view/base/requirejs-config.js
14: uiComponent: 'Magento_Ui/js/lib/core/collection',
İçinde layout.js, Magento aşağıdakine eşdeğer bir çalışma kodu var.
//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*/})
}
Gerçekten merak uyandırmak için, toplama modeline bakarsanız ve yürütme yolunu izlerseniz collection, bunun hem lib/core/element/elementmodül hem de modül tarafından geliştirilmiş bir javascript nesnesi olduğunu keşfedeceksiniz lib/core/class. Bu özelleştirmeleri araştırmak bu cevabın kapsamı dışındadır.
Bir kez başlatıldığında, layout.jsbunu objectkayıt defterinde saklar . Bu, Nakavt ciltleri işlemeye başladığında ve özel scopeciltleme ile karşılaştığında
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<!-- snip -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!-- snip -->
</div>
Magento bu nesneyi kayıt defterinden geri getirecek ve içindeki şeyler için görünüm modeli olarak bağlayacaktır div. Başka bir deyişle, getTemplateNakavt etiketsiz bağlayıcıyı ( <!-- ko template: getTemplate() --><!-- /ko -->) çağırdığında çağrılan getTemplateyöntem new collectionnesnedeki yöntemdir .