Answers:
要了解checkoutProvider
和displayArea
是,你必须先了解你正在寻找的范围:jsLayout
。
jsLayout
是结帐页面上JavaScript UI元素的一堆JavaScript配置。如果您查看module-checkout/view/frontend/templates/onepage.phtml
,则会注意到以下x-magento-init
-data:
<script type="text/x-magento-init">
{
"#checkout": {
"Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
}
}
</script>
这就是一切的开始。它指出:
对于element
#checkout
,Magento_Ui/js/core/app
使用以下信息初始化-component:...
它接收的信息是在布局XML中创建的信息:jsLayout
。现在,这意味着您的XML 中的所有内容现在都传递给Magento_Ui/js/core/app
-component(暂时不包括插件,布局处理器和其他东西……)
现在,我将不深入探讨如何module-ui/view/base/web/js/core/app.js
精简一切,因为这会使这篇文章非常非常长,但是摘要如下:
Magento_Ui/js/core/app
-component创建checkout
-component。uiComponent
(这是一个非常通用的组件,可用于推迟使用您自己的自定义UI组件。它带有基本的剔除模板渲染和内容)。Magento_Checkout/web/frontend/template/onepage.html
。errors
,estimation
,steps
,等...)steps
孩子也将是uiComponent
。现在到你displayArea
和provider
-question:正如你在上面看到的,一切都映射到的javascrip类。第一次看到使用displayArea
是在创建类型为steps
-component的时候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“映射”到特定的一组UI组件。要知道这一点很重要,因为它允许我们仅通过处理XML布局就可以将UI组件移动到布局中的其他位置,就像您使用phtml
在服务器端呈现的模板一样。只需覆盖displayArea
,您就可以在其他任何地方渲染任何JavaScript UI组件(假设目标区域也渲染在某个地方)。
现在,您的第二个问题是:provider
。就像我们查找一样displayArea
,我们应该首先开始查看UI组件Magento_Checkout/js/view/form/element/email
。如果我们看一下requirejs-config.js
,我们终于找到了module-checkout/view/frontend/web/js/view/form/element/email.js
。
但是... provider
在此类中不使用。因此,让我们看看是否可以在它扩展的类中找到任何东西:(Component
又是我们的uiComponent
-class)。
但是...也不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
。
以我的理解,所有这些都与UI组件中的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
-node中的使用。基本上,它告诉Knockout该子元素应该在称为“ messages”的区域中呈现。
现在看一下顶部registration.html
:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
这行Knockout代码的基本作用是:遍历displayArea'messages '中存在的所有子元素,并渲染它们。
基本上,如果您问我,命名会有些混乱。为什么要在一个地方使用“ displayArea”而在另一个地方使用“ region”。但是也许我的假设是完全错误的。也许Magento核心开发人员可以对此有所启发?
getRegion
,我的内心崩溃了。谢谢您的回答,非常有帮助!