คำตอบ:
เพื่อให้เข้าใจถึงสิ่งที่checkoutProviderและเป็นครั้งแรกที่คุณจะต้องเข้าใจถึงขอบเขตที่คุณกำลังมองหาใน:displayAreajsLayout
jsLayoutคือการกำหนดค่า JavaScript จำนวนมากสำหรับองค์ประกอบ JavaScript UI บนหน้าเช็คเอาต์ หากคุณดู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>
นี่คือจุดเริ่มต้นของทุกสิ่ง มันระบุว่า:
สำหรับองค์ประกอบ
#checkoutเริ่มต้น - ส่วนMagento_Ui/js/core/appประกอบด้วยข้อมูลต่อไปนี้: ...
และข้อมูลที่ได้รับเป็นข้อมูลที่สร้างขึ้นในรูปแบบ jsLayoutXML: ตอนนี้หมายความว่าทุกอย่างใน XML ของคุณตอนนี้ถูกส่งผ่านไปยังMagento_Ui/js/core/app-component (ปล่อยปลั๊กอินและตัวประมวลผลการจัดวางและสิ่งต่าง ๆ ออกจากสมการในขณะนี้ ... )
ตอนนี้ฉันจะไม่ลงลึกในรายละเอียดmodule-ui/view/base/web/js/core/app.jsว่าจะทำให้ทุกอย่างเดือดลงได้อย่างไรเพราะนั่นจะทำให้โพสต์นี้ยาวมาก แต่บทสรุปก็คือ:
Magento_Ui/js/core/appส่วนประกอบสร้าง - checkoutส่วนประกอบuiComponent(นี่เป็นส่วนประกอบทั่วไปมากที่สามารถใช้เพื่อเลื่อนองค์ประกอบ UI ที่กำหนดเองของคุณเองมาพร้อมกับการแสดงผลเทมเพลตและสิ่งที่น่าพิศวงพื้นฐาน)Magento_Checkout/web/frontend/template/onepage.htmlมันจะให้เราแม่แบบerrors, estimation, stepsฯลฯ ... )stepsuiComponentตอนนี้เพื่อไปที่displayAreaและproviderคำถามของคุณ: ตามที่คุณเห็นด้านบนทุกอย่างจะทำแผนที่กับคลาส JavaScrip ครั้งแรกที่เราเห็นการใช้displayAreaคือเมื่อเราสร้างsteps-component uiComponentซึ่งเป็นชนิดที่ ดังนั้นจะเป็นผู้สมัครตรรกะที่จะมองหาการใช้งานของuiComponentdisplayArea
ตอนนี้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;
},
ดังนั้นสิ่งนี้จะมีผลบังคับใช้คือ 'จับคู่ ui' กับคอมโพเนนต์ UI กลุ่มหนึ่ง สิ่งนี้เป็นสิ่งสำคัญที่ต้องทราบเนื่องจากช่วยให้เราสามารถย้ายส่วนประกอบ UI ไปยังตำแหน่งอื่น ๆ ในโครงร่างโดยเพียงแค่จัดการเลย์เอาต์ XML เช่นเดียวกับที่คุณทำกับphtmlเท็มเพลตที่แสดงผลฝั่งเซิร์ฟเวอร์ เพียงแค่แทนที่displayAreaและคุณสามารถแสดงผลคอมโพเนนต์ UI UI ได้ทุกที่อื่น (เนื่องจากพื้นที่เป้าหมายถูกแสดงผลที่ใดที่หนึ่ง)
ตอนนี้สำหรับคำถามที่สองของคุณ: provider. เช่นเดียวกับที่เราเคยมองขึ้นdisplayAreaเราควรเริ่มมองหาที่ตัวแทน UI Magento_Checkout/js/view/form/element/emailแรกซึ่งเป็น และถ้าเรามองไปที่ในที่สุดเราก็พบว่าrequirejs-config.jsmodule-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/shippingcheckoutProvider
นั่นทำให้เรามีคำถามสองข้อ:
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 และฉันเชื่อว่านี่เป็นวิธีการทำงาน น่าเสียดายที่ไม่มีเอกสารมากนักหากคุณต้องการดำดิ่งลงสู่ก้นมหาสมุทร
6 เดือนหลังจากคำตอบดั้งเดิมของฉันฉันคิดว่าฉันสามารถให้คำตอบที่ดีกว่าในสิ่งที่displayAreaเป็น
ในความเข้าใจของฉันมันมาพร้อมกับ Knockouts ' getTemplate()-method, the getRegion()-method, และ children ใน UI Components เป็นตัวอย่างที่ดีของเรื่องนี้สามารถมองเห็นได้เมื่อคุณกำลังตรวจสอบและvendor/magento/module-checkout/view/frontend/templates/registration.phtmlvendor/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 โดยทั่วไปจะบอกสิ่งที่น่าพิศวงว่าองค์ประกอบเด็กคนนี้ควรจะแสดงผลในภูมิภาคที่เรียกว่า'ข้อความ'
ตอนนี้ดูที่ด้านบนของregistration.html:
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
สิ่งที่เป็นบรรทัดของรหัสที่น่าพิศวงโดยทั่วไปคือ: มันวนซ้ำองค์ประกอบเด็กทั้งหมดที่มีอยู่ใน'ข้อความ' displayArea และทำให้พวกเขา
โดยพื้นฐานแล้วการตั้งชื่อค่อนข้างสับสนถ้าคุณถามฉัน ทำไมคุณถึงใช้'displayArea'ในที่เดียวและ'ภูมิภาค'ในที่อื่น แต่ข้อสันนิษฐานของฉันอาจไม่ถูกต้องทั้งหมด บางทีนักพัฒนาหลักของ Magento อาจส่องแสงเพิ่มเติมเล็กน้อย
getRegionอยู่เรื่อย ๆ ขอบคุณสำหรับคำตอบทั้งสองทางมีประโยชน์มาก!