Ответы:
Для того, чтобы понять , что 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
и мой ум просто взрывается. Кстати, спасибо за оба ответа, очень полезно!