Mã PHP cho thành phần UI hiển thị khởi tạo javascript trông như thế này
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app":{
"types":{...},
"components":{...},
}
}
}
</script>
Đoạn mã này trong trang có nghĩa là Magento sẽ gọi Magento_Ui/js/core/app
mô-đun RequireJS để tìm nạp lại một cuộc gọi lại, sau đó gọi cuộc gọi lại đó đi qua trong {types:..., components:...}
đối tượng JSON làm đối số ( data
bên dưới)
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
define([
'./renderer/types',
'./renderer/layout',
'Magento_Ui/js/lib/ko/initialize'
], function (types, layout) {
'use strict';
return function (data) {
types.set(data.types);
layout(data.components);
};
});
Đối tượng dữ liệu chứa tất cả dữ liệu cần thiết để kết xuất thành phần UI, cũng như cấu hình liên kết các chuỗi nhất định với các mô-đun Magento RequireJS nhất định. Ánh xạ đó xảy ra trong các mô-đun types
và layout
RequireJS. Ứng dụng này cũng tải Magento_Ui/js/lib/ko/initialize
thư viện RequireJS. Các initialize
đá mô-đun tắt tích hợp KnockoutJS Magento.
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js
define([
'ko',
'./template/engine',
'knockoutjs/knockout-repeat',
'knockoutjs/knockout-fast-foreach',
'knockoutjs/knockout-es5',
'./bind/scope',
'./bind/staticChecked',
'./bind/datepicker',
'./bind/outer_click',
'./bind/keyboard',
'./bind/optgroup',
'./bind/fadeVisible',
'./bind/mage-init',
'./bind/after-render',
'./bind/i18n',
'./bind/collapsible',
'./bind/autoselect',
'./extender/observable_array',
'./extender/bound-nodes'
], function (ko, templateEngine) {
'use strict';
ko.setTemplateEngine(templateEngine);
ko.applyBindings();
});
Mỗi bind/...
mô-đun RequireJS riêng lẻ thiết lập một ràng buộc tùy chỉnh duy nhất cho Knockout.
Các extender/...
mô-đun RequireJS thêm một số phương thức trợ giúp vào các đối tượng KnockoutJS riêng.
Magento cũng mở rộng chức năng của công cụ mẫu javascript của Knockout trong ./template/engine
mô-đun RequireJS.
Cuối cùng, Magento gọi applyBindings()
đối tượng KnockoutJS. Đây thường là nơi chương trình Knockout sẽ liên kết mô hình xem với trang HTML - tuy nhiên, Magento gọiapplyBindings
mà không có mô hình xem. Điều này có nghĩa là Knockout sẽ bắt đầu xử lý trang dưới dạng xem, nhưng không bị ràng buộc dữ liệu.
Trong một thiết lập Knockout chứng khoán, điều này sẽ là một chút ngớ ngẩn. Tuy nhiên, do các ràng buộc Knockout tùy chỉnh đã đề cập trước đó, có rất nhiều cơ hội để Knockout thực hiện.
Chúng tôi quan tâm đến phạm vi ràng buộc. Bạn có thể thấy rằng trong HTML này, cũng được hiển thị bởi hệ thống Thành phần UI UI.
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
<div class="spinner">
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<!-- ko template: getTemplate() --><!-- /ko -->
<script type="text/x-magento-init">
</script>
</div>
Cụ thể là data-bind="scope: 'customer_listing.customer_listing'">
thuộc tính. Khi Magento khởi động applyBindings
, Knockout sẽ thấy scope
ràng buộc tùy chỉnh này và gọi ./bind/scope
mô-đun RequireJS. Khả năng áp dụng một ràng buộc tùy chỉnh là KnockoutJS thuần túy. Việc thực hiện ràng buộc phạm vi là điều Magento Inc. đã làm.
Việc thực hiện ràng buộc phạm vi là tại
#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js
Bit quan trọng trong tập tin này là ở đây
var component = valueAccessor(),
apply = applyComponents.bind(this, el, bindingContext);
if (typeof component === 'string') {
registry.get(component, apply);
} else if (typeof component === 'function') {
component(apply);
}
Không đi sâu vào chi tiết, registry.get
phương thức sẽ lấy ra một đối tượng đã được tạo bằng cách sử dụng chuỗi trong component
biến làm định danh và truyền nó cho applyComponents
phương thức làm tham số thứ ba. Mã định danh chuỗi là giá trị của scope:
( customer_listing.customer_listing
ở trên)
Trong applyComponents
function applyComponents(el, bindingContext, component) {
component = bindingContext.createChildContext(component);
ko.utils.extend(component, {
$t: i18n
});
ko.utils.arrayForEach(el.childNodes, ko.cleanNode);
ko.applyBindingsToDescendants(component, el);
}
về cơ bản, lệnh gọi createChildContext
sẽ tạo ra một đối tượng viewModel mới dựa trên đối tượng thành phần đã được khởi tạo và sau đó áp dụng nó cho tất cả các phần tử hậu duệ của bản gốc div
được sử dụng data-bind=scope:
.
Vì vậy, các đối tượng thành phần đã được khởi tạo là gì? Nhớ cuộc gọi để layout
quay lại app.js
?
#File: vendor/magento/module-ui/view/base/web/js/core/app.js
layout(data.components);
Các layout
chức năng / mô-đun sẽ rơi vào thông qua năm data.components
(một lần nữa, số liệu này được lấy từ các đối tượng thông qua năm qua text/x-magento-init
). Đối với mỗi đối tượng mà nó tìm thấy, nó sẽ tìm kiếm một config
đối tượng và trong đối tượng cấu hình đó, nó sẽ tìm kiếm một component
khóa. Nếu nó tìm thấy một khóa thành phần, nó sẽ
Sử dụng RequireJS
để trả về một thể hiện của mô-đun - như thể mô-đun được gọi trong requirejs
/ define
phụ thuộc.
Gọi ví dụ mô-đun đó như là một hàm tạo javascript
Lưu trữ đối tượng kết quả trong registry
đối tượng / mô-đun
Vì vậy, đó là rất nhiều để tham gia. Đây là một đánh giá nhanh, sử dụng
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
<div class="spinner">
<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<!-- ko template: getTemplate() --><!-- /ko -->
<script type="text/x-magento-init">
</script>
</div>
như một điểm khởi đầu. Các scope
giá trị customer_listing.customer_listing
.
Nếu chúng ta nhìn vào đối tượng JSON từ khi text/x-magento-init
khởi tạo
{
"*": {
"Magento_Ui/js/core/app": {
/* snip */
"components": {
"customer_listing": {
"children": {
"customer_listing": {
"type": "customer_listing",
"name": "customer_listing",
"children": /* snip */
"config": {
"component": "uiComponent"
}
},
/* snip */
}
}
}
}
}
}
Chúng ta thấy components.customer_listing.customer_listing
đối tượng có một config
đối tượng và đối tượng config đó có một component
đối tượng được đặt thành uiComponent
. Các uiComponent
chuỗi là một module RequireJS. Trong thực tế, bí danh RequireJS tương ứng với Magento_Ui/js/lib/core/collection
mô-đun.
vendor/magento/module-ui/view/base/requirejs-config.js
14: uiComponent: 'Magento_Ui/js/lib/core/collection',
Trong layout.js
, Magento đã chạy mã tương đương như sau.
//The actual code is a bit more complicated because it
//involves jQuery's promises. This is already a complicated
//enough explanation without heading down that path
require(['Magento_Ui/js/lib/core/collection'], function (collection) {
object = new collection({/*data from x-magento-init*/})
}
Đối với những người thực sự tò mò, nếu bạn xem mô hình bộ sưu tập và theo con đường thực thi của nó, bạn sẽ phát hiện ra đó collection
là một đối tượng javascript được tăng cường cả bởi lib/core/element/element
mô-đun và lib/core/class
mô-đun. Nghiên cứu các tùy chỉnh này nằm ngoài phạm vi của câu trả lời này.
Sau khi khởi tạo, layout.js
lưu trữ này object
trong sổ đăng ký. Điều này có nghĩa là khi Knockout bắt đầu xử lý các ràng buộc và gặp scope
ràng buộc tùy chỉnh
<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
<!-- snip -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!-- snip -->
</div>
Magento sẽ lấy đối tượng này ra khỏi sổ đăng ký và liên kết nó làm mô hình xem cho những thứ bên trong div
. Nói cách khác, getTemplate
phương thức được gọi khi Knockout gọi ràng buộc tagless ( <!-- ko template: getTemplate() --><!-- /ko -->
) là getTemplate
phương thức trên new collection
đối tượng.