Câu trả lời:
Để hiểu những gì checkoutProvider
và displayArea
là gì , trước tiên bạn phải hiểu phạm vi bạn đang tìm kiếm : jsLayout
.
jsLayout
là một loạt các cấu hình JavaScript cho các thành phần UI JavaScript trên trang thanh toán. Nếu bạn nhìn vào module-checkout/view/frontend/templates/onepage.phtml
, bạn sẽ nhận thấy các x-magento-init
-data sau :
<script type="text/x-magento-init">
{
"#checkout": {
"Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
}
}
</script>
Đây là nơi mà tất cả bắt đầu. Nó nói:
Đối với phần tử
#checkout
, khởi tạo phần tửMagento_Ui/js/core/app
với thông tin sau: ...
Và thông tin mà nó nhận được là thông tin được tạo trong bố cục XML : jsLayout
. Bây giờ, điều này có nghĩa là mọi thứ trong XML của bạn bây giờ được chuyển qua Magento_Ui/js/core/app
-component (để lại các plugin và bộ xử lý bố cục và các công cụ ngoài phương trình trong thời điểm này ...)
Bây giờ, tôi sẽ không đi sâu vào chi tiết về cách làm module-ui/view/base/web/js/core/app.js
sôi mọi thứ, bởi vì điều đó sẽ làm cho bài đăng này rất, rất dài, nhưng tóm tắt là thế này:
Magento_Ui/js/core/app
phần tạo ra một thành checkout
phần.uiComponent
(đây là một thành phần rất chung có thể được sử dụng để trì hoãn các thành phần UI tùy chỉnh của riêng bạn. Nó đi kèm với kết xuất và mẫu kết xuất mẫu cơ bản).Magento_Checkout/web/frontend/template/onepage.html
.errors
, estimation
, steps
, vv ...)steps
con cũng sẽ là a uiComponent
.Bây giờ để đi đến displayArea
và provider
câu hỏi của bạn : Như bạn đã thấy ở trên, mọi thứ ánh xạ tới các lớp JavaScrip. Lần đầu tiên chúng ta thấy việc sử dụng displayArea
là khi chúng ta tạo thành steps
phần, thuộc loại uiComponent
. Vì vậy, uiComponent
sẽ là một ứng cử viên hợp lý để tìm kiếm việc sử dụng displayArea
.
Bây giờ, a uiComponent
là một lớp JavaScript của loại Magento_Ui/js/lib/core/collection
. (Bạn có thể tra cứu điều này module-ui/view/base/requirejs-config.js
). Bản đồ này để module-ui/view/base/web/js/lib/core/collection.js
. Ở đây chúng tôi thấy cách sử dụng sau đây:
/**
* 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;
},
Vì vậy, những gì nó có hiệu lực, nó 'ánh xạ' một uiComponent đến một nhóm các thành phần UI nhất định. Điều này rất quan trọng để biết, vì nó cho phép chúng ta di chuyển các thành phần UI đến các vị trí khác trong bố cục, chỉ bằng cách thao tác bố cục XML, giống như bạn sẽ làm điều này với các phtml
mẫu được hiển thị phía máy chủ. Chỉ cần ghi đè displayArea
và bạn có thể kết xuất bất kỳ Thành phần giao diện người dùng JavaScript nào ở bất kỳ nơi nào khác (với điều kiện là khu vực đích cũng được hiển thị ở đâu đó).
Bây giờ cho câu hỏi thứ hai của bạn : provider
. Giống như chúng ta đã nhìn lên displayArea
, chúng ta nên bắt đầu nhìn vào Thành phần UI trước Magento_Checkout/js/view/form/element/email
. Và nếu chúng ta nhìn vào requirejs-config.js
, cuối cùng chúng ta cũng tìm thấy module-checkout/view/frontend/web/js/view/form/element/email.js
.
Nhưng ... không provider
được sử dụng trong lớp này. Vì vậy, hãy xem liệu chúng ta có thể tìm thấy bất cứ thứ gì trong lớp mà nó mở rộng không: Component
(lại là uiComponent
lớp của chúng ta ).
Nhưng ... không provider
tốt. Chà, uiComponent
chỉ đơn giản là kéo dài Element
(nằm ở module-ui/view/base/web/js/lib/core/element/element.js
), vì vậy chúng ta hãy nhìn qua đó:
/**
* 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;
},
Chơi lô tô! Nó chỉ ra rằng nhà cung cấp được sử dụng như một nguồn để lấy dữ liệu từ đó. Nếu chúng ta nhìn vào hàm tạo của Element
mặc định, bạn sẽ thấy rằng theo mặc định, nó được đặt thành trống:
provider: '',
Vì vậy, trở lại cấu hình của chúng tôi. Nếu bây giờ chúng ta đọc cấu hình của mình, chúng ta sẽ hiểu rằng vật phẩm shippingAddress
là một thành phần của Magento_Checkout/js/view/shipping
, nó lấy dữ liệu của nó từ checkoutProvider
.
Vì vậy, điều đó để lại cho chúng tôi hai câu hỏi:
checkoutProvider
xác định?Chà, nếu bạn cuộn xuống phía dưới checkout_index_index.xml
, bạn sẽ nhận thấy rằng nó chẳng khác gì một vani uiComponent
:
<item name="checkoutProvider" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
</item>
Và nếu bạn nhìn vào module-checkout/view/frontend/web/js/view/shipping.js
, bạn sẽ thấy rằng nó được sử dụng như thế này:
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);
});
});
Thành thật mà nói: đây là nơi phân tích của tôi dừng lại, bởi vì nó cũng khó tìm kiếm và đầu tư những gì đang diễn ra, nhưng tôi hy vọng ai đó có thể nhận nó từ đây ...
Tôi biết nó có liên quan đến việc registry.async()
trả về một phương thức được thực thi ngay lập tức với hàm gọi lại làm đối số, nhưng người khác cần giải thích điều này ...
* Khước từ trách nhiệm: Bằng mọi cách, xin vui lòng sửa lỗi cho tôi nếu tôi sai! Không thử bất kỳ điều nào ở trên, nhưng tôi đã làm việc gần một năm nay với Magento 2 và tôi tin rằng đây là cách nó hoạt động. Thật không may, không có nhiều tài liệu nếu bạn muốn lặn xuống đáy đại dương Magento.
6 tháng sau câu trả lời ban đầu của tôi, tôi nghĩ rằng tôi có thể cung cấp một câu trả lời tốt hơn về những gì displayArea
.
Theo hiểu biết của tôi, tất cả đều đi kèm với Knockouts ' getTemplate()
-method, getRegion()
-method và trẻ em trong các Thành phần UI. Một ví dụ tốt về điều này có thể được nhìn thấy khi bạn kiểm tra vendor/magento/module-checkout/view/frontend/templates/registration.phtml
và vendor/magento/module-checkout/view/frontend/web/template/registration.html
.
Trong registration.phtml
, bạn sẽ thấy Thành phần giao diện người dùng Magento mặc định có con:
<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>
Lưu ý việc sử dụng displayArea
trong children
-node. Về cơ bản, nó nói với Knockout rằng phần tử con này sẽ được hiển thị trong một khu vực được gọi là 'tin nhắn' .
Bây giờ hãy xem trên cùng của registration.html
:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
Dòng mã Knockout này về cơ bản là gì, nó lặp lại trên tất cả các phần tử con có trong displayArea 'message' và hiển thị chúng.
Về cơ bản, việc đặt tên hơi khó hiểu nếu bạn hỏi tôi. Tại sao bạn lại sử dụng 'displayArea' ở một nơi và 'khu vực' ở một nơi khác. Nhưng có lẽ giả định của tôi là hoàn toàn không chính xác. Có lẽ một nhà phát triển cốt lõi Magento có thể tỏa sáng hơn một chút về điều này?
getRegion
và đầu óc tôi cứ nổ tung. Cảm ơn bạn cho cả hai câu trả lời bằng cách này, rất hữu ích!