UIコンポーネントのPHPコードは、次のようなjavascriptの初期化をレンダリングします
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app":{
"types":{...},
"components":{...},
}
}
}
</script>
このページのコードは、MagentoがMagento_Ui/js/core/app
RequireJSモジュールを呼び出してコールバックを取得し、そのコールバックを呼び出して{types:..., components:...}
JSONオブジェクトを引数として渡すことを意味します(data
以下)
#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);
};
});
データオブジェクトには、UIコンポーネントのレンダリングに必要なすべてのデータと、特定の文字列を特定のMagento RequireJSモジュールにリンクする構成が含まれています。そのマッピングはRequireJSモジュールtypes
でlayout
行われます。アプリケーションは、Magento_Ui/js/lib/ko/initialize
RequireJSライブラリもロードします。このinitialize
モジュールは、MagentoのKnockoutJS統合を開始します。
/**
* 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();
});
個々のbind/...
RequireJSモジュールは、Knockoutの単一のカスタムバインディングをセットアップします。
extender/...
RequireJSモジュールは、ネイティブKnockoutJSオブジェクトにいくつかのヘルパーメソッドを追加します。
Magentoは、./template/engine
RequireJSモジュールのKnockoutのjavascriptテンプレートエンジンの機能も拡張します。
最後に、MagentoはapplyBindings()
KnockoutJSオブジェクトを呼び出します。これは通常、KnockoutプログラムがビューモデルをHTMLページにバインドする場所ですが、MagentoはビューモデルapplyBindings
なしで呼び出します。これは、Knockoutがページをビューとして処理し始めますが、データがバインドされていないことを意味します。
ストックノックアウトのセットアップでは、これは少しばかげているでしょう。ただし、前述のカスタムKnockoutバインディングのため、Knockoutが処理を実行する機会はたくさんあります。
スコープバインディングに興味があります。このHTMLでも、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>
具体的には、data-bind="scope: 'customer_listing.customer_listing'">
属性。Magentoが開始されるとapplyBindings
、Knockoutはこのカスタムscope
バインディングを確認し、./bind/scope
RequireJSモジュールを呼び出します。カスタムバインディングを適用する機能は、純粋なKnockoutJSです。スコープバインディングの実装は、Magento Inc.が行ったことです。
スコープバインディングの実装は
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js
このファイルの重要な部分はこちらです
var component = valueAccessor(),
apply = applyComponents.bind(this, el, bindingContext);
if (typeof component === 'string') {
registry.get(component, apply);
} else if (typeof component === 'function') {
component(apply);
}
詳細に入ることなく、registry.get
メソッドはcomponent
変数内の文字列を識別子として使用して既に生成されたオブジェクトを引き出しapplyComponents
、3番目のパラメーターとしてメソッドに渡します。文字列識別子はscope:
(customer_listing.customer_listing
上記)の値です
に 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);
}
の呼び出しcreateChildContext
は、基本的に、既にインスタンス化されたコンポーネントオブジェクトに基づいて新しいviewModelオブジェクトを作成し、それをdiv
使用した元のすべての子孫要素に適用しますdata-bind=scope:
。
それで、すでにインスタンス化されたコンポーネントオブジェクトは何ですか?layout
戻るための呼び出しを覚えていますapp.js
か?
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
layout(data.components);
layout
機能/モジュールは、渡さに下降しますdata.components
(再度、このデータを介して渡されたオブジェクトから来ていますtext/x-magento-init
)。見つかったオブジェクトごとにオブジェクトを探し、その構成オブジェクトでキーconfig
を探しcomponent
ます。コンポーネントキーが見つかると、
/ 依存関係RequireJS
でモジュールが呼び出されたかのように、モジュールインスタンスを返すために使用します。requirejs
define
そのモジュールインスタンスをjavascriptコンストラクタとして呼び出す
結果のオブジェクトをregistry
オブジェクト/モジュールに保存します
だから、それは多くのことを取り入れる必要があります。
<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>
出発点として。scope
値ですcustomer_listing.customer_listing
。
text/x-magento-init
初期化からJSONオブジェクトを見ると
{
"*": {
"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_listing
オブジェクトが持っているconfig
オブジェクトを、そのconfigオブジェクトが持っているcomponent
に設定されていますオブジェクトをuiComponent
。uiComponent
文字列は、RequireJSモジュールです。実際、そのMagento_Ui/js/lib/core/collection
モジュールに対応するRequireJSエイリアスです。
vendor/magento/module-ui/view/base/requirejs-config.js
14: uiComponent: 'Magento_Ui/js/lib/core/collection',
ではlayout.js
、Magentoは次と同等のコードを実行しました。
//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*/})
}
好奇心For盛な人のために、コレクションモデルを見て、その実行パスをたどると、モジュールとモジュールのcollection
両方によって拡張されたjavascriptオブジェクトであることがわかります。これらのカスタマイズの調査は、この回答の範囲外です。lib/core/element/element
lib/core/class
インスタンス化したら、layout.js
これobject
をレジストリに保存します。これは、ノックアウトは、バインディングの処理を開始し、カスタム遭遇したscope
結合を
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<!-- snip -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!-- snip -->
</div>
Magentoはこのオブジェクトをレジストリからフェッチし、内のオブジェクトのビューモデルとしてバインドしますdiv
。つまり、getTemplate
Knockoutがタグレスバインディング(<!-- ko template: getTemplate() --><!-- /ko -->
)を呼び出すときに呼び出されるgetTemplate
メソッドは、new collection
オブジェクトのメソッドです。