Magento 2 - Alan Storm 博客 - 介绍 UI 组件
Magento 2 - Alan Storm 博客 - 介绍 UI 组件
来源: https://alanstorm.com/magento_2_introducing_ui_components/
UI 组件是组建用户界面元素的一个强有力的方法,并且很多新的后台控制台都建立在这个功能之上。今天我们将深入了解 UI 组件系统的目标,包括尽可能地深入了解执行细节,并且最后结束会用 pestle 生成 grid/listing UI 组件。
理解 UI 组件目的最简单的方法是讨论 Magento 1 的后台用户界面形成的代码。这是一个 Magento 1 布局更新 XML 代码的例子。
1 js_css prototype/windows/themes/default.css lib/prototype/windows/themes/magento.css
你看给一个页面添加产品编辑表单甚至更复杂。
Magento 2 的 UI 组件打算解决这个难题,并且大大地简化了每个人的布局句柄 XML 文件。
- 简化了布局句柄 XML 文件
- 把管理用户界面元素从 HTML+JavaScript 变成了“纯 JavaScript” 自定义组件系统
- 是由更小的组件建造更复杂的 UI 组件的系统
- 作为 JSON 为 UI 组件预渲染数据,跟 Mangento 后台数据对象紧密地绑定在一起
- 使用 AJAX 来更新数据
- 引入一个新的 DSL 来创建以上所有
除非你对复杂的执行细节感兴趣,不然你可能想要直接跳到最后我们用 pestle 创建一个 UI 组件的地方。
如果你查看未解析的 HTML 页面资源,
总之,Magento 1 用 HTML 中渲染了一个列表,然后用 JavaScript 增强了用户界面的功能。然而 Magento 2 仍然使用一些 HTML 骨架,也把大部分的用户元素的渲染转换成了 RequireJS 模块和 KnockoutJS 模板。
{
"*": {
"Magento_Ui/js/core/app": {
"types": /*...*/
"components": {
"cms_block_listing": {
"children": {
"cms_block_listing": {
/*...*/
"children": {
"listing_top": {
"type": "container",
"name": "listing_top",
"children": {
"bookmarks": {/*...*/},
"columns_controls": {/*...*/},
"fulltext": {/*...*/},
"listing_filters": {/*...*/},
"listing_massaction": {/*...*/},
"listing_paging": {/*...*/}
},
正如我们之前提到的,最初的 getTemplate 的调用最终会渲染很多子组件。第一个 KnockoutJS 模板之所以命名为 collection.html 是因为它是很多不同的 UI 组件的集合。不过今天我们涉及这整个渲染过程。
今天我们涉及的是 PHP 开发人员如何控制在 JavaScript 树中渲染什么。如果我们回到
#File: vendor/magento//module-cms/view/adminhtml/ui_component/cms_block_listing.xml- cms_block_listing.cms_block_listing_data_source
- cms_block_listing.cms_block_listing_data_source
- cms_block_columns
- add
- Add New Block
- primary
- */*/new
- 为根级别的 listing 节点查询 PHP 类名和默认参数
- 用 argument 节点作为构造函数的参数来实例化这个类
#File: vendor/magento/module-ui/view/base/ui_component/etc/definition.xml- templates/listing/default
- 1
- mui/index/render
- uiComponent
$uiComponent = new MagentoUiComponentListing( $context, $components, [ 'template'=>'templates/listing/default', 'save_parameters_in_session'=>'1', 'client_root'=>'mui/index/render', 'config'=>[ 'component'=>'uiComponent' ], 'js_config'=>[ 'provider'=>'', 'deps'=>'' ], 'spinner'=>'cms_block_columns', 'buttons'=>[ 'add'=>[ 'name'=>'add', 'label'=>'Add New Block', 'class'=>'primary', 'url'=>'*/*/new' ] ], ] )
以上参数的数据来自于合并在一起的节点。每一个参数有不同影响——但是我们感兴趣的是 templates/listing/default 这个参数。它指的是渲染这个 UI 组件的 XHTML 模板。template/listing/default 这个字符串对应以下这个模板。
#File: vendor/magento//module-ui/view/base/ui_component/templates/listing/default.xhtml
#File: vendor/magento/module-ui/TemplateEngine/Xhtml/Result.phppublic function __toString()
{ try { //...
$this->appendLayoutConfiguration(); $result = $this->compiler->postprocessing($this->template->__toString());
} catch (Exception $e) { $this->logger->critical($e->getMessage()); $result = $e->getMessage();
} return $result;
}//...public function appendLayoutConfiguration()
{ $layoutConfiguration = $this->wrapContent( json_encode( $this->structure->generate($this->component)
)
); $this->template->append($layoutConfiguration);
}//...protected function wrapContent($content)
{ return '';
}
#File: vendor/magento//module-cms/view/adminhtml/ui_component/cms_block_listing.xml- cms_block_listing.cms_block_listing_data_source
- cms_block_listing.cms_block_listing_data_source
- cms_block_columns
- add
- Add New Block
- primary
- */*/new
#File: vendor/magento//module-cms/view/adminhtml/ui_component/cms_block_listing.xml
我们看到更多的配置的 UI 组件。UI 组件中任何名字不为 argument 的子节点被当做父对象的子节点。比如,当 Magento 渲染 listing 组件时,它也在 definitions.xml 中查找 listingToolbar,columns 等的类名和参数。
#File: vendor/magento/module-ui/view/base/ui_component/etc/definition.xml
$uiComponent = new MagentoUiComponentListing(...); $listingToolbar = new MagentoUiComponentContainer(...); $columns = new MagentoUiComponentListingColumns(...); $uiComponent->addComponent($listingToolbar); $uiComponent->addComponent($columns);
#File: vendor/magento//module-cms/view/adminhtml/ui_component/cms_block_listing.xml- Magento_Ui/js/grid/listing
#File: vendor/magento//module-ui/view/base/web/js/grid/listing.js
define([
'ko',
'underscore',
'Magento_Ui/js/lib/spinner',
'uiLayout',
'uiCollection'], function (ko, _, loader, layout, Collection) { 'use strict'; return Collection.extend({
defaults: {
template: 'ui/grid/listing',
} //...
});
});
#File: vendor/magento//module-cms/view/adminhtml/ui_component/cms_block_listing.xml- cms_block_listing.cms_block_listing_data_source
- cms_block_listing.cms_block_listing_data_source
- cms_block_columns
- add
- Add New Block
- primary
- */*/new
{
"*": {
"Magento_Ui/js/core/app": {
"types": {/*...*/},
"components": {
"cms_block_listing": {
"children": {
"cms_block_listing": {/*...*/},
"cms_block_listing_data_source": {
"type": "dataSource",
"name": "cms_block_listing_data_source",
"dataScope": "cms_block_listing",
"config": {
"data": {
"items": [],
"totalRecords": 0
},
"component": "Magento_Ui/js/grid/provider",
"update_url": "http://magento-2-1-0.dev/admin/mui/index/render/key/e628fdf18db9219474935e85ab3f25b445287503a00a230704b4168c566f8059/",
"storageConfig": {
"indexField": "block_id"
},
"params": {
"namespace": "cms_block_listing"
}
}
}
}
}
}
}
}
}
Magento 将在 dataSource 组件中查询组成 UI 组件的实际数据(比如,model 已渲染的数据集合)。
- UI 组件渲染 x-magento-init 脚本,这个脚本填入了 KnockoutJS view models 的全局注册表。
- UI 组件也渲染 HTML 骨架,HTML 使用 KnockoutJS 和自定义 scope 绑定来渲染构成组件的 DOM 节点。
- ui_component XML 文件是一个特定领域的语言来表示 UI 组件对象的嵌套的等级,最终,Magento 将会用它来渲染 x-magento-init 脚本的 JSON 。
- ui_component 的 XML 节点 name 用来查询 PHP 类以示例化。
- Magento 把所以子
节点作为那个类的构造函数的参数。 - Magento 使用任何名为
的子节点来渲染用在 UI 组件中的实际数据(比如,网格列表信息)。 - 其他任何子节点将会被用在渲染子 UI 组件,这些子 UI 组件将遵循父级的规则。
- 顶层 UI 节点配置一个 XHTML 模板,Magento 通过 PHP 渲染它。
- UI 组件节点配置 RequireJS 模块,Magento 把 RequireJS 模块当做 KnockoutJS view model 构造函数。
就像你看到的,虽然 UIComponent 标签很好地简化了 Magento 2 的布局句柄 XML 文件,他们仍然隐藏了很多更复杂的 UI 渲染系统,包括前端和后台的 Magento 系统代码,并且要求开发人员理解 Magneto 的自定义 RequireJS 和 KnockoutJS 。
$ pestle.phar magento2:generate:ui:grid Which Module? (Pulsestorm_Gridexample)] Pulsestorm_ToDoCrud Create a unique ID for your Listing/Grid! (pulsestorm_gridexample_log)] pulsestorm_todo_listing What Resource Collection Model should your listing use? (MagentoCmsModelResourceModelPageCollection)] PulsestormToDoCrudModelResourceModelTodoItemCollection What's the ID field for you model? (pulsestorm_gridexample_log_id)] pulsestorm_todocrud_todoitem_id
Which Module 参数告诉 pestle 你想要创建你栅格列表的 Magento 模块。一般来说,跟 collection 文件是同一个模块,但是在这个惯例上没有硬性规定。之前的教程里我们已经指定了 Pulsestorm_ToDoCrud 模块。
Create a unique ID for your Listing/Grid! 这个参数是我们想要的 UI 组件 的名称。这将是在
What Resource Collection Model should your listing use? 这个参数是 model 集合用的类名。我们想要栅格列表展示 Pulsestorm_ToDoCrud model,所以我们使用 PulsestormToDoCrudModelResourceModelTodoItemCollection 这个集合。
What’s the ID field for you model? 这个参数是一个 model 的数据库表的主键数据库列。
- text
- Item Title
- 20
除了生成 UI 组件的 pulsestorm_todo_listing.xml 文件,pestle 也生成了一个 “提供数据” 类和一个“操作页面” 类。
#File: app/code/Pulsestorm/ToDoCrud/Ui/Component/Listing/DataProviders/Pulsestorm/Todo/Listing.php collection = $collectionFactory->create(); } }
#File: app/code/Pulsestorm/ToDoCrud/Ui/Component/Listing/Column/Pulsestormtodolisting/PageActions.php
getData("name");
$id = "X";
if(isset($item["pulsestorm_todocrud_todoitem_id"]))
{
$id = $item["pulsestorm_todocrud_todoitem_id"];
}
$item[$name]["view"] = [
"href"=>$this->getContext()->getUrl(
"adminhtml/pulsestorm_todo_listing/viewlog",["id"=>$id]),
"label"=>__("Edit")
];
}
}
return $dataSource;
}
}
66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 谢谢小威
