Відповіді:
Для того, щоб зрозуміти , що checkoutProvider
і displayArea
є, ви повинні спочатку зрозуміти область , яку ви шукаєте в: jsLayout
.
jsLayout
це купа конфігурації JavaScript для елементів інтерфейсу JavaScript на сторінці оформлення замовлення. Якщо ви подивитесь module-checkout/view/frontend/templates/onepage.phtml
, ви помітите наступні x-magento-init
дані:
<script type="text/x-magento-init">
{
"#checkout": {
"Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
}
}
</script>
Тут все починається. У ньому зазначено:
Для елемента
#checkout
ініціалізуйтеMagento_Ui/js/core/app
-компонент із такою інформацією: ...
А інформація , яку вона отримує це інформація , створена в макеті XML: jsLayout
. Це означає, що все у вашому XML зараз передається до Magento_Ui/js/core/app
-компонента (залишаючи плагіни та процесори компонування та інше з рівняння на даний момент ...)
Зараз я не збираюся заглиблюватися в деталі, як module-ui/view/base/web/js/core/app.js
все зводить, бо це зробило б цю публікацію дуже-дуже довгою, але резюме таке:
Magento_Ui/js/core/app
Компонентний створює checkout
-компонент.uiComponent
(це дуже загальний компонент, який можна використовувати для відстрочення власних користувальницьких компонентів інтерфейсу. Поставляється з базовим візуалізацією шаблонів вибивання та ін.).Magento_Checkout/web/frontend/template/onepage.html
.errors
, estimation
, steps
і т.д. ...)steps
-Child буде також uiComponent
.Тепер , щоб дістатися до displayArea
і provider
-question: Як ви вже бачили вище, всі карти на класи JavaScrip. Перший раз, коли ми бачимо використання, displayArea
це коли ми створюємо steps
-компонент, який має тип uiComponent
. Тож uiComponent
було б логічним кандидатом шукати використання displayArea
.
Тепер uiComponent
клас класу JavaScript Magento_Ui/js/lib/core/collection
. (Ви можете подивитися це вгорі module-ui/view/base/requirejs-config.js
). Це карти для module-ui/view/base/web/js/lib/core/collection.js
. Тут ми бачимо наступне використання:
/**
* Synchronizes multiple elements arrays with a core '_elems' container.
* Performs elemets grouping by theirs 'displayArea' property.
* @private
*
* @returns {Collection} Chainable.
*/
_updateCollection: function () {
var _elems = compact(this._elems),
grouped;
grouped = _elems.filter(function (elem) {
return elem.displayArea && _.isString(elem.displayArea);
});
grouped = _.groupBy(grouped, 'displayArea');
_.each(grouped, this.updateRegion, this);
this.elems(_elems);
return this;
},
Отже, що це робить насправді, воно "відображає" uiComponent на певну групу компонентів інтерфейсу. Це важливо знати, оскільки це дозволяє нам переміщувати компоненти інтерфейсу користувача в інші місця в макеті, просто маніпулюючи компонуванням XML так, як ви це робите з phtml
шаблонами, які надаються на стороні сервера. Просто замініть displayArea
, і ви можете візуалізувати будь-який компонент інтерфейсу JavaScript у будь-якому іншому місці (враховуючи, що цільова область також десь надана).
Тепер для вашого другого запитання: provider
. Так само, як ми подивилися вгору displayArea
, ми повинні почати спочатку переглядати компонент інтерфейсу, який є Magento_Checkout/js/view/form/element/email
. І якщо ми подивимось на requirejs-config.js
, ми нарешті знайдемо module-checkout/view/frontend/web/js/view/form/element/email.js
.
Але ... ні provider
в цьому класі не використовується. Тож давайте просто подивимось, чи зможемо ми знайти що-небудь у класі, який він розширює: Component
(який uiComponent
знову - наш клас).
Але ... також не provider
так. Ну uiComponent
просто розширюється Element
(що знаходиться на module-ui/view/base/web/js/lib/core/element/element.js
), так що давайте просто подивимось там:
/**
* Parses 'modules' object and creates
* async wrappers for specified components.
*
* @returns {Element} Chainable.
*/
initModules: function () {
_.each(this.modules, function (name, property) {
if (name) {
this[property] = this.requestModule(name);
}
}, this);
if (!_.isFunction(this.source)) {
this.source = registry.get(this.provider);
}
return this;
},
Бінго! Виявляється, провайдер використовується як джерело для отримання даних з. Якщо ми подивимось на конструктор Element
, ви побачите, що за замовчуванням воно встановлено порожнім:
provider: '',
Тож повернемося до нашої конфігурації. Якщо ми зараз прочитаємо нашу конфігурацію, то зрозуміємо, що елемент shippingAddress
є компонентом Magento_Checkout/js/view/shipping
, що отримує його дані з checkoutProvider
.
Отже, ми залишаємо два питання:
checkoutProvider
визначено?Що ж, якщо ви прокрутите донизу checkout_index_index.xml
, ви помітите, що це не що інше, як ваніль uiComponent
:
<item name="checkoutProvider" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
</item>
А якщо ви подивитесь module-checkout/view/frontend/web/js/view/shipping.js
, то побачите, що він використовується так:
registry.async('checkoutProvider')(function (checkoutProvider) {
var shippingAddressData = checkoutData.getShippingAddressFromData();
if (shippingAddressData) {
checkoutProvider.set(
'shippingAddress',
$.extend({}, checkoutProvider.get('shippingAddress'), shippingAddressData)
);
}
checkoutProvider.on('shippingAddress', function (shippingAddressData) {
checkoutData.setShippingAddressFromData(shippingAddressData);
});
});
Якщо чесно: на цьому мій аналіз зупиняється, тому що мені також важко шукати та інвестувати те, що відбувається, але я сподіваюся, що хтось ще може взяти це звідси ...
Я знаю, що це має щось registry.async()
спільне з методом повернення, який негайно виконується з функцією зворотного виклику як аргумент, але комусь іншому потрібно пояснити це ...
* Відмова: У будь-якому випадку, будь ласка, виправте мене, якщо я помиляюся! Я не пробував реально описаного вище, але я майже рік працюю з Magento 2, і я вважаю, що це працює. На жаль, не так багато документації, якщо ви хочете пірнути на дно океану Магенто.
Через 6 місяців після моєї первинної відповіді я думаю, що можу дати кращу відповідь на те, що displayArea
є.
На моє розуміння, все це поєднується з -методом Knockouts getTemplate()
, getRegion()
-методом та дітьми в компонентах інтерфейсу користувача. Хороший приклад цього можна побачити при обстеженні vendor/magento/module-checkout/view/frontend/templates/registration.phtml
та vendor/magento/module-checkout/view/frontend/web/template/registration.html
.
У ньому registration.phtml
ви побачите компонент інтерфейсу Magento UI, який має дітей:
<script type="text/x-magento-init">
{
"#registration": {
"Magento_Ui/js/core/app": {
"components": {
"registration": {
"component": "Magento_Checkout/js/view/registration",
"config": {
"registrationUrl": "<?php /* @escapeNotVerified */ echo $block->getCreateAccountUrl(); ?>",
"email": "<?php /* @escapeNotVerified */ echo $block->getEmailAddress(); ?>"
},
"children": {
"errors": {
"component": "Magento_Ui/js/view/messages",
"sortOrder": 0,
"displayArea": "messages",
"config": {
"autoHideTimeOut": -1
}
}
}
}
}
}
}
}
</script>
Зверніть увагу на використання displayArea
у children
-ноді. В основному, це говорить нокауту, що цей дочірній елемент повинен бути відображений у регіоні, який називається "повідомлення" .
Тепер подивіться на верхню частину registration.html
:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
Що в основному робить цей рядок коду Knockout, це: він повторює всі дочірні елементи, які є у "повідомленнях" displayArea , і відображає їх.
В основному, називання трохи заплутане, якщо ви запитаєте мене. Чому б ви використовували "displayArea" в одному місці, а "region" в іншому. Але, можливо, моє припущення є абсолютно невірним. Можливо, розробник Magento core міг би просвітити на цьому трохи більше світла?
getRegion
а мій розум просто розгортається. Дякую за обидві відповіді, до речі, дуже корисно!