Ответы:
Для того, чтобы понять , что 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-component следующей информацией: ...
А информация , которую она получает это информация , созданная в макете 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.
Теперь a 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 UI где-либо еще (учитывая, что целевая область также отображается где-то).
Теперь для вашего второго вопроса: 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, и я верю, что так оно и есть. К сожалению, нет большого количества документации, если вы хотите погрузиться на дно океана Magento.
Через 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 по умолчанию, который имеет детей:
<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-node. По сути, он сообщает Knockout, что этот дочерний элемент должен отображаться в области, называемой «messages» .
Теперь взгляните на верхнюю часть registration.html:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
То, что в основном делает эта строка кода Knockout: она перебирает все дочерние элементы, присутствующие в «сообщениях» displayArea , и отображает их.
По сути, названия немного сбивают с толку, если вы спросите меня. Почему вы используете «displayArea» в одном месте и «регион» в другом месте. Но, возможно, мое предположение совершенно неверно. Возможно, разработчик ядра Magento мог бы пролить немного света на это?
getRegionи мой ум просто взрывается. Кстати, спасибо за оба ответа, очень полезно!