Respostas:
Para entender o que checkoutProvider
e displayArea
são, você deve primeiro entender o alcance que você está procurando em: jsLayout
.
jsLayout
é um monte de configuração do JavaScript para os elementos da interface do usuário do JavaScript na página de checkout. Se você olhar module-checkout/view/frontend/templates/onepage.phtml
, notará os seguintes x-magento-init
dados:
<script type="text/x-magento-init">
{
"#checkout": {
"Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
}
}
</script>
Isso é onde tudo começa. Afirma:
Para o elemento
#checkout
, inicialize oMagento_Ui/js/core/app
componente com as seguintes informações: ...
E a informação que recebe é a informação criado no XML de layout: jsLayout
. Agora, isso significa que tudo em seu XML agora é passado para o Magento_Ui/js/core/app
componente (deixando plug-ins e processadores de layout e outras coisas fora da equação no momento ...)
Agora, não vou me aprofundar nos detalhes de como module-ui/view/base/web/js/core/app.js
tudo se resume, porque isso tornaria este post muito, muito longo, mas o resumo é este:
Magento_Ui/js/core/app
componente cria um checkout
componente.uiComponent
(este é um componente muito genérico que pode ser usado para adiar seus próprios componentes de interface do usuário personalizados. Ele vem com renderização básica de modelo de knockout e outras coisas).Magento_Checkout/web/frontend/template/onepage.html
.errors
, estimation
, steps
, etc ...)steps
criança também será a uiComponent
.Agora, para chegar à sua displayArea
e provider
-question: Como você viu acima, tudo é mapeado para as classes JavaScrip. A primeira vez que vemos o uso de displayArea
é quando nós criamos o steps
-component, que é do tipo uiComponent
. Então, uiComponent
seria um candidato lógico para procurar o uso de displayArea
.
Agora, a uiComponent
é uma classe JavaScript do tipo Magento_Ui/js/lib/core/collection
. (Você pode procurar isso em module-ui/view/base/requirejs-config.js
). Isso mapeia para module-ui/view/base/web/js/lib/core/collection.js
. Aqui vemos o seguinte uso:
/**
* 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;
},
Portanto, o que isso faz é "mapear" um uiComponent para um determinado grupo de componentes da interface do usuário. É importante saber, porque isso nos permite mover os componentes da interface do usuário para outros locais no layout, apenas manipulando o layout XML, assim como você faria com phtml
modelos que são renderizados no servidor. Basta substituir o displayArea
e você pode renderizar qualquer componente da interface do usuário JavaScript em qualquer outro lugar (considerando que a área de destino também é renderizada em algum lugar).
Agora, para a sua segunda pergunta: provider
. Assim como procuramos displayArea
, devemos começar a olhar primeiro para o componente da interface do usuário Magento_Checkout/js/view/form/element/email
. E se olharmos para o requirejs-config.js
, finalmente encontramos module-checkout/view/frontend/web/js/view/form/element/email.js
.
Mas ... não provider
é usado nesta classe. Então, vamos ver se conseguimos encontrar algo na classe que se estenda: Component
(que é nossa uiComponent
classe-novamente).
Mas ... não provider
também. Bem, uiComponent
simplesmente se estende Element
(que está localizado em module-ui/view/base/web/js/lib/core/element/element.js
), então vamos dar uma olhada lá:
/**
* 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! Acontece que o provedor é usado como uma fonte para buscar dados. Se olharmos para o construtor de Element
, você verá que, por padrão, está definido como vazio:
provider: '',
Então, de volta à nossa configuração. Se agora lermos nossa configuração, entenderemos que o item shippingAddress
é um componente Magento_Checkout/js/view/shipping
, que busca seus dados no checkoutProvider
.
Então, isso nos deixa com duas perguntas:
checkoutProvider
definido?Bem, se você rolar até o final checkout_index_index.xml
, notará que não passa de uma baunilha uiComponent
:
<item name="checkoutProvider" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
</item>
E se você olhar module-checkout/view/frontend/web/js/view/shipping.js
, verá que é usado assim:
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);
});
});
Para ser honesto: é aqui que a minha análise para, porque também me torna difícil pesquisar e investir o que está acontecendo, mas espero que alguém possa buscá-lo daqui ...
Eu sei que tem algo a ver com o registry.async()
retorno de um método que é executado imediatamente com uma função de retorno de chamada como argumento, mas alguém precisa explicar isso ...
* Aviso: Por todos os meios, por favor, corrija-me se eu estiver errado! Ainda não tentei nenhuma das opções acima, mas já trabalho há quase um ano com o Magento 2 e acredito que é assim que funciona. Infelizmente, não há muita documentação se você quiser mergulhar no fundo do oceano Magento.
Seis meses após minha resposta original, acho que posso fornecer uma resposta melhor sobre o que displayArea
é.
No meu entendimento, tudo isso vem junto com o getTemplate()
método dos Knockouts , o getRegion()
método e os filhos nos componentes da interface do usuário. Um bom exemplo disso pode ser visto quando você está examinando vendor/magento/module-checkout/view/frontend/templates/registration.phtml
e vendor/magento/module-checkout/view/frontend/web/template/registration.html
.
Em registration.phtml
, você verá um componente Magento UI padrão que tem filhos:
<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>
Observe o uso de displayArea
no children
-node. Basicamente, ele informa ao Knockout que esse elemento filho deve ser renderizado em uma região chamada 'mensagens' .
Agora dê uma olhada no topo de registration.html
:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
O que essa linha de código Knockout basicamente faz é: itera sobre todos os elementos filhos que estão presentes nas 'mensagens' displayArea e os renderiza.
Basicamente, o nome é um pouco confuso se você me perguntar. Por que você usaria 'displayArea' em um local e 'region' em outro local. Mas talvez minha suposição esteja totalmente incorreta. Talvez um desenvolvedor central do Magento possa esclarecer um pouco mais isso?
getRegion
e minha mente apenas implode. Obrigado por ambas as respostas, a propósito, muito útil!