Odpowiedzi:
Aby zrozumieć, co checkoutProvider
i displayArea
są, trzeba najpierw zrozumieć zakres szukasz w: jsLayout
.
jsLayout
to kilka konfiguracji JavaScript dla elementów interfejsu użytkownika JavaScript na stronie kasy. Jeśli spojrzysz na to module-checkout/view/frontend/templates/onepage.phtml
, zauważysz następujące x-magento-init
dane:
<script type="text/x-magento-init">
{
"#checkout": {
"Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
}
}
</script>
Od tego wszystko się zaczyna. W Stanach:
Dla elementu
#checkout
zainicjujMagento_Ui/js/core/app
-component następującymi informacjami: ...
A informacje otrzymuje się informacje tworzone w XML układ: jsLayout
. Oznacza to, że wszystko w twoim XML jest teraz przekazywane do Magento_Ui/js/core/app
-komponentu (pozostawiając wtyczki, procesory układu i inne rzeczy poza równaniem na razie ...)
Teraz nie będę zagłębiał się w szczegóły, jak module-ui/view/base/web/js/core/app.js
wszystko się sprowadza, ponieważ dzięki temu ten post byłby bardzo, bardzo długi, ale podsumowanie jest następujące:
Magento_Ui/js/core/app
-Component tworzy checkout
-component.uiComponent
(jest to bardzo ogólny komponent, którego można użyć do odroczenia własnego niestandardowego komponentu interfejsu użytkownika. Jest wyposażony w podstawowe renderowanie szablonów i tym podobne).Magento_Checkout/web/frontend/template/onepage.html
.errors
, estimation
, steps
, etc ...)steps
-Child będzie również uiComponent
.Przejdźmy teraz do pytania displayArea
i provider
: Pytanie: Jak widzieliśmy powyżej, wszystko odwzorowuje się na klasy JavaScrip. Po raz pierwszy widzimy użycie, displayArea
gdy tworzymy steps
-komponent, który jest tego typu uiComponent
. uiComponent
Byłby więc logicznym kandydatem do szukania zastosowania displayArea
.
A uiComponent
to klasa JavaScript tego typu Magento_Ui/js/lib/core/collection
. (Możesz to sprawdzić w module-ui/view/base/requirejs-config.js
). To odwzorowuje na module-ui/view/base/web/js/lib/core/collection.js
. Tutaj widzimy następujące zastosowanie:
/**
* 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;
},
Więc co to w efekcie powoduje, „mapuje” komponent uiComponent do pewnej grupy komponentów interfejsu użytkownika. Jest to ważne, ponieważ pozwala nam przenosić komponenty interfejsu użytkownika do innych lokalizacji w układzie, po prostu manipulując układem XML, podobnie jak w przypadku phtml
szablonów renderowanych po stronie serwera. Wystarczy zastąpić displayArea
i można renderować dowolny komponent interfejsu użytkownika JavaScript gdziekolwiek indziej (biorąc pod uwagę, że obszar docelowy jest również renderowany gdzieś).
Teraz do drugiego pytania: provider
. Tak jak spojrzeliśmy w górę displayArea
, powinniśmy najpierw zacząć przyglądać się komponentowi interfejsu użytkownika Magento_Checkout/js/view/form/element/email
. A jeśli spojrzymy na to requirejs-config.js
, w końcu znajdziemy module-checkout/view/frontend/web/js/view/form/element/email.js
.
Ale ... nie provider
jest używane w tej klasie. Zobaczmy więc, czy możemy znaleźć coś w klasie, którą on rozszerza: Component
(która jest uiComponent
ponownie naszą klasą ).
Ale ... też nie provider
. Cóż, uiComponent
po prostu rozszerza Element
(który znajduje się w module-ui/view/base/web/js/lib/core/element/element.js
), więc spójrzmy tam:
/**
* 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;
},
Bingo! Okazuje się, że dostawca jest wykorzystywany jako źródło pobierania danych. Jeśli spojrzymy na konstruktor Element
, zobaczysz, że domyślnie jest ustawiony na pusty:
provider: '',
Wróćmy do naszej konfiguracji. Jeśli teraz przeczytamy naszą konfigurację, zrozumiemy, że element shippingAddress
jest składnikiem Magento_Checkout/js/view/shipping
, który pobiera z niego dane checkoutProvider
.
Pozostają nam zatem dwa pytania:
checkoutProvider
zdefiniowane?Cóż, jeśli przewiniesz na dół checkout_index_index.xml
, zauważysz, że to nic innego jak wanilia uiComponent
:
<item name="checkoutProvider" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
</item>
A jeśli spojrzysz module-checkout/view/frontend/web/js/view/shipping.js
, zobaczysz, że jest on używany w następujący sposób:
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);
});
});
Szczerze mówiąc: w tym miejscu kończy się moja analiza, ponieważ trudno mi również wyszukiwać i inwestować w to, co się dzieje, ale mam nadzieję, że ktoś inny może to stąd odebrać ...
Wiem, że ma to coś wspólnego ze registry.async()
zwróceniem metody, która jest natychmiast wykonywana z funkcją wywołania zwrotnego jako argumentem, ale ktoś inny musi to wyjaśnić ...
* Uwaga: W każdym razie, proszę mnie poprawić, jeśli się mylę! Naprawdę nie próbowałem żadnego z powyższych, ale prawie od roku pracuję z Magento 2 i wierzę, że tak to działa. Niestety nie ma zbyt wiele dokumentacji, jeśli chcesz nurkować na dnie Oceanu Magento.
6 miesięcy po mojej pierwotnej odpowiedzi myślę, że mogę udzielić lepszej odpowiedzi na to, co displayArea
jest.
W moim rozumieniu wszystko to łączy się z getTemplate()
metodą Knockouta , getRegion()
metodą i dziećmi w komponentach interfejsu użytkownika. Dobry przykład tego można zobaczyć podczas badania vendor/magento/module-checkout/view/frontend/templates/registration.phtml
i vendor/magento/module-checkout/view/frontend/web/template/registration.html
.
W registration.phtml
zobaczysz domyślny komponent interfejsu użytkownika Magento, który ma dzieci:
<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>
Zwróć uwagę na użycie displayArea
w children
-node. Zasadniczo mówi Knockoutowi, że ten element potomny powinien być renderowany w regionie zwanym „wiadomościami” .
Teraz spójrz na górę registration.html
:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
Co ta linia kodu Knockout zasadzie robi, jest to iteracje nad wszystkich elementów podrzędnych, które są obecne w displayArea „Wiadomości” , i czyni je.
Zasadniczo nazwa jest nieco myląca, jeśli mnie o to poprosisz. Dlaczego miałbyś używać „displayArea” w jednym miejscu, a „region” w innym miejscu. Ale może moje założenie jest całkowicie błędne. Być może twórca rdzenia Magento mógłby rzucić na to nieco więcej światła?
getRegion
a mój umysł po prostu imploduje. Nawiasem mówiąc, dziękuję za obie odpowiedzi, bardzo pomocne!