TL; DR
Đây thực sự là một vấn đề thú vị.
Đây là cách tôi hiểu hệ thống nhưng tôi có thể không đúng 100%.
Như bạn đã thấy, nhấp vào cột tiêu đề sẽ tạo một yêu cầu AJAX theo tuyến đường sau: /admin_key/mui/index/render
với các tham số sau:
- bộ lọc [giữ chỗ]
- isAjax
- không gian tên
- phân trang [hiện tại]
- phân trang [kích thước trang]
- Tìm kiếm
- sắp xếp [hướng]
- sắp xếp [trường]
Cái cuối cùng là trường mà bạn đang sắp xếp lưới của mình.
Tuyến đường này được khai báo theo mặc định trong app/code/Magento/Ui/view/base/ui_component/etc/definition.xml
:
<insertListing class="Magento\Ui\Component\Container">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/components/insert-listing</item>
<item name="update_url" xsi:type="url" path="mui/index/render"/>
<item name="render_url" xsi:type="url" path="mui/index/render"/>
<item name="autoRender" xsi:type="boolean">false</item>
<item name="dataLinks" xsi:type="array">
<item name="imports" xsi:type="boolean">true</item>
<item name="exports" xsi:type="boolean">false</item>
</item>
<item name="realTimeLink" xsi:type="boolean">true</item>
</item>
</argument>
</insertListing>
Nhưng trong một danh sách ui_component XML, nó cũng được khai báo:
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
<item name="update_url" xsi:type="url" path="mui/index/render"/>
<item name="storageConfig" xsi:type="array">
<item name="indexField" xsi:type="string">page_id</item>
</item>
</item>
</argument>
Tuyến này được xử lý app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php
dựa trên tham số không gian tên (thường là tên của Thành phần UI của bạn)
public function execute()
{
if ($this->_request->getParam('namespace') === null) {
$this->_redirect('admin/noroute');
return;
}
$component = $this->factory->create($this->_request->getParam('namespace'));
$this->prepareComponent($component);
$this->_response->appendBody((string) $component->render());
}
Trong đó prepareComponent
phương thức được đệ quy trên các thành phần con:
protected function prepareComponent(UiComponentInterface $component)
{
foreach ($component->getChildComponents() as $child) {
$this->prepareComponent($child);
}
$component->prepare();
}
Khi thành phần cột được chuẩn bị, việc sắp xếp cột được xử lý bởi app/code/Magento/Ui/Component/Listing/Columns/Column.php
:
public function prepare()
{
$this->addFieldToSelect();
$dataType = $this->getData('config/dataType');
if ($dataType) {
$this->wrappedComponent = $this->uiComponentFactory->create(
$this->getName(),
$dataType,
array_merge(['context' => $this->getContext()], (array) $this->getData())
);
$this->wrappedComponent->prepare();
$wrappedComponentConfig = $this->getJsConfig($this->wrappedComponent);
// Merge JS configuration with wrapped component configuration
$jsConfig = array_replace_recursive($wrappedComponentConfig, $this->getJsConfig($this));
$this->setData('js_config', $jsConfig);
$this->setData(
'config',
array_replace_recursive(
(array)$this->wrappedComponent->getData('config'),
(array)$this->getData('config')
)
);
}
$this->applySorting();
parent::prepare();
}
Trong đó applySorting()
phương thức dựa trên tham số sắp xếp và nó chỉ đơn giản là thêm thứ tự cho nhà cung cấp dữ liệu:
protected function applySorting()
{
$sorting = $this->getContext()->getRequestParam('sorting');
$isSortable = $this->getData('config/sortable');
if ($isSortable !== false
&& !empty($sorting['field'])
&& !empty($sorting['direction'])
&& $sorting['field'] === $this->getName()
) {
$this->getContext()->getDataProvider()->addOrder(
$this->getName(),
strtoupper($sorting['direction'])
);
}
}
Khi mọi thành phần được chuẩn bị, lớp hành động sẽ kết xuất lại thành phần đó (một lần nữa đệ quy) cho phản hồi:
$this->_response->appendBody((string) $component->render());
Tôi nghĩ đó là những bước quan trọng của PHP về những gì xảy ra trong quá trình sắp xếp.
Bây giờ với JS, các URL kết xuất và cập nhật (được khai báo ở definition.xml
trên) được gán cho phần tử trong app/code/Magento/Ui/view/base/web/js/form/components/insert.js
:
return Element.extend({
defaults: {
content: '',
template: 'ui/form/insert',
showSpinner: true,
loading: false,
autoRender: true,
visible: true,
contentSelector: '${$.name}',
externalData: [],
params: {
namespace: '${ $.ns }'
},
renderSettings: {
url: '${ $.render_url }',
dataType: 'html'
},
updateSettings: {
url: '${ $.update_url }',
dataType: 'json'
},
imports: {},
exports: {},
listens: {},
links: {
value: '${ $.provider }:${ $.dataScope}'
},
modules: {
externalSource: '${ $.externalProvider }'
}
}
Vẫn trong tệp này, có một requestData
phương thức được sử dụng để truy xuất dữ liệu AJAX:
requestData: function (params, ajaxSettings) {
var query = utils.copy(params);
ajaxSettings = _.extend({
url: this['update_url'],
method: 'GET',
data: query,
dataType: 'json'
}, ajaxSettings);
this.loading(true);
return $.ajax(ajaxSettings);
}
Bạn có thể thấy rằng phương thức này được gọi khi render()
phương thức được gọi:
$.async({
component: this.name,
ctx: '.' + this.contentSelector
}, function (el) {
self.contentEl = $(el);
self.startRender = true;
params = _.extend({}, self.params, params || {});
request = self.requestData(params, self.renderSettings);
request
.done(self.onRender)
.fail(self.onError);
});
Một khi điều này được thực hiện, một phương thức gọi lại được gọi để áp dụng dữ liệu. Đó là onRender()
:
onRender: function (data) {
this.loading(false);
this.set('content', data);
this.isRendered = true;
this.startRender = false;
}
Tôi nghĩ đó là nơi mà nội dung mới đang được áp dụng.