开发前必读

开发环境请打开debug模式

Dcat Admin提供一些开发工具(如代码生成器)需要在 debug 模式下才能使用。 建议开发者在开发环境打开debug模式,把.env配置文件中的参数APP_DEBUG值设置为true即可。

按需引入JS脚本

Dcat Admin 使用 jquery-pjax 构建无刷新页面(单页应用),并且支持按需加载 JS 脚本,支持在任意的页面方法(模板文件除外)中引入JS脚本,每个页面只需加载当前页面所需要使用到的 js 脚本。

示例:

写一个自定义页面,这个页面组件需要引入一些前端静态资源文件

{tip} Dcat Admin构建的是一个单页应用,加载的JS脚本只会执行一次,所以初始化操作不能直接放在JS脚本中,应该使用Admin::script方法载入。

  1. <?php
  2. use Illuminate\Contracts\Support\Renderable;
  3. use Dcat\Admin\Admin;
  4. class Card implements Renderable
  5. {
  6. public static $js = [
  7. // js脚本不能直接包含初始化操作,否则页面刷新后无效
  8. 'xxx/js/card.min.js',
  9. ];
  10. public static $css = [
  11. 'xxx/css/card.min.css',
  12. ];
  13. public function script()
  14. {
  15. return <<<JS
  16. console.log('所有JS脚本都加载完了');
  17. // 初始化操作
  18. $('xxx').card();
  19. JS;
  20. }
  21. public function render()
  22. {
  23. // 在这里可以引入你的js或css文件
  24. Admin::js(static::$js);
  25. Admin::css(static::$css);
  26. // 需要在页面执行的JS代码,例如初始化代码
  27. // 通过 Admin::script 设置的JS代码会自动在所有JS脚本都加载完毕后执行
  28. Admin::script($this->script());
  29. return view('...')->render();
  30. }
  31. }

在控制器中使用这个组件

  1. use Dcat\Admin\Layout\Content;
  2. use Card;
  3. class HomeController
  4. {
  5. public function index(Content $content)
  6. {
  7. // 使用上面的Card组件
  8. // Card组件需要用到的静态文件只会在当前请求加载
  9. // 其他请求不会加载
  10. return $content->body(new Card());
  11. }
  12. }

在页面中添加JS代码

由于加入了页面按需加载JS脚本的功能,所以在本项目内添加的JS代码都必须使用Dcat.ready方法监听JS脚本加载完毕事件,在此事件内的JS代码会在所有JS脚本都加载完毕后才执行。

使用 Dcat\Admin\Admin::script 方法添加的代码会自动放在Dcat.ready方法内执行。

  1. <?php
  2. use Dcat\Admin\Admin;
  3. use Dcat\Admin\Layout\Content;
  4. class UserController
  5. {
  6. public function index(Content $content)
  7. {
  8. Admin::script(
  9. <<<JS
  10. (function () {
  11. // 如果有定义局部变量的需求,最好放在匿名函数内,防止变量污染
  12. var name = 'test';
  13. console.log('所有JS脚本都加载完毕啦~~', name)
  14. })()
  15. JS
  16. );
  17. return $content->header(...)->body(...);
  18. }
  19. }

如果是在模板文件中添加JS代码,则需要把代码放在Dcat.ready内执行

  1. <script>
  2. // 用 Dcat.ready() 代替 $()
  3. // 此方法会在所有 js 脚本加载完成后执行
  4. Dcat.ready(function () {
  5. // 写入你的 js 代码
  6. console.log('所有 js 脚本加载完毕啦~~');
  7. });
  8. </script>

页面内容和布局

{tip} 页面内容的布局功能是Dcat Admin的基石,掌握了这个功能的用法,可以非常轻松的使用Dcat Admin构建页面或扩展功能,请大家一定要认真阅读。

Dcat Admin的布局可参考后台首页的布局文件app/Admin/Controllers/HomeController.phpindex()方法。

Dcat\Admin\Layout\Content类用来实现内容区的布局。Content::body($content)方法用来添加页面内容。

一个简单的后台页面代码如下:

  1. use Dcat\Admin\Layout\Content;
  2. public function index(Content $content)
  3. {
  4. // 选填
  5. $content->header('填写页面头标题');
  6. // 选填
  7. $content->description('填写页面描述小标题');
  8. // 添加面包屑导航
  9. $content->breadcrumb(
  10. ['text' => '首页', 'url' => '/admin'],
  11. ['text' => '用户管理', 'url' => '/admin/users'],
  12. ['text' => '编辑用户']
  13. );
  14. // 填充页面body部分,这里可以填入任何可被渲染的对象
  15. return $content->body('hello world');
  16. }

其中 $content->body() 方法是 $content->row() 的别名方法,可以接受任何可字符串化的对象作为参数,可以是字符串、数字、包含了__toString方法的对象,实现了RenderableHtmlable接口的对象,包括laravel的视图。

布局

dcat-admin的布局使用bootstrap的栅格系统,每行的长度是12,下面是几个简单的示例:

添加一行内容:

  1. $content->row('hello')
  2. ---------------------------------
  3. |hello |
  4. | |
  5. | |
  6. | |
  7. | |
  8. | |
  9. ---------------------------------

行内添加多列:

  1. $content->row(function(Row $row) {
  2. $row->column(4, 'foo');
  3. $row->column(4, 'bar');
  4. $row->column(4, 'baz');
  5. });
  6. ----------------------------------
  7. |foo |bar |baz |
  8. | | | |
  9. | | | |
  10. | | | |
  11. | | | |
  12. | | | |
  13. ----------------------------------
  14. $content->row(function(Row $row) {
  15. $row->column(4, 'foo');
  16. $row->column(8, 'bar');
  17. });
  18. ----------------------------------
  19. |foo |bar |
  20. | | |
  21. | | |
  22. | | |
  23. | | |
  24. | | |
  25. ----------------------------------

列中添加行:

  1. $content->row(function (Row $row) {
  2. $row->column(4, 'xxx');
  3. $row->column(8, function (Column $column) {
  4. $column->row('111');
  5. $column->row('222');
  6. $column->row('333');
  7. });
  8. });
  9. ----------------------------------
  10. |xxx |111 |
  11. | |---------------------|
  12. | |222 |
  13. | |---------------------|
  14. | |333 |
  15. | | |
  16. ----------------------------------

列中添加行, 行内再添加列:

  1. $content->row(function (Row $row) {
  2. $row->column(4, 'xxx');
  3. $row->column(8, function (Column $column) {
  4. $column->row('111');
  5. $column->row('222');
  6. $column->row(function(Row $row) {
  7. $row->column(6, '444');
  8. $row->column(6, '555');
  9. });
  10. });
  11. });
  12. ----------------------------------
  13. |xxx |111 |
  14. | |---------------------|
  15. | |222 |
  16. | |---------------------|
  17. | |444 |555 |
  18. | | | |
  19. ----------------------------------

构建无菜单栏页面 (full)

通过以上方法构建的页面默认是带有左边菜单栏和顶部导航栏的, 但有时候我们会需要构建一个没有菜单栏和顶部导航栏的完整页面,如登陆页面,或需要在IFRAME中加载的页面等等。

这时候就可以用 Content::full 这个方法了,调用了此方法后渲染出来的页面是不带菜单栏和顶部导航栏的,并且还可以使用 Dcat Admin 中的所有的功能和组件的,可以显著地提高效率。

下面将通过登录页的实现来演示此功能的用法

控制器

  1. use Dcat\Admin\Layout\Content;
  2. class AuthController extends Controller
  3. {
  4. public function getLogin(Content $content)
  5. {
  6. if ($this->guard()->check()) {
  7. return redirect($this->redirectPath());
  8. }
  9. // 使用full方法构建登陆页面
  10. return $content->full()->body(view($this->view));
  11. }
  12. ...
  13. }

下面是登陆功能的模板内容,因为控制器中使用了Content::full方法构建页面,所以不需要在模板中写head,也不需要关心引入哪些静态资源,只需写当前页面的HTML即可,并且还可以使用Dcat Admin中的所有功能,如下面用到的表单提交功能。

  1. <style>
  2. html body {background: #fff;}
  3. </style>
  4. <link rel="stylesheet" href="{{ admin_asset('@admin/css/pages/authentication.css') }}">
  5. <section class="row flexbox-container">
  6. <!-- 这里是你的登陆页面HTML代码 -->
  7. ...
  8. </section>
  9. <script>
  10. Dcat.ready(function () {
  11. // ajax表单提交
  12. $('#login-form').form({
  13. validate: true,
  14. success: function (data) {
  15. if (! data.status) {
  16. Dcat.error(data.message);
  17. return false;
  18. }
  19. Dcat.success(data.message);
  20. location.href = data.redirect;
  21. return false;
  22. }
  23. });
  24. });
  25. </script>

这个登陆页面使用了ajax表单提交功能,并且附带了按钮loading效果,比原来的登陆功能用户体验更好,大家可以点这里体验

事件

系统会在Dcat\Admin\Layout\Content类被实例化时和render()方法被调用时触发以下两个事件,开发者可以在这两个事件中改变或添加一些行为。

实例化 (resolving)

通过Content::resolving方法设置的回调函数会在Dcat\Admin\Layout\Content类被实例化时触发;

  1. use Dcat\Admin\Layout\Content;
  2. Content::resolving(function (Content $content) {
  3. $content->view('app.admin.content');
  4. });

构建页面 (composing)

通过Content::composing方法设置的回调函数会在Dcat\Admin\Layout\Content::render方法被调用时触发;

  1. use Dcat\Admin\Layout\Content;
  2. Content::composing(function (Content $content) {
  3. $content->view('app.admin.content');
  4. });

构建完成 (composed)

通过Content::composed方法设置的回调函数会在所有通过Content::rowContent::body方法设置的内容都构建完毕后触发。

  1. use Dcat\Admin\Layout\Content;
  2. class IndexController
  3. {
  4. public function index(Content $content)
  5. {
  6. Content::composed(function (Content $content) {
  7. // Grid已执行render方法
  8. });
  9. return $content->body(function ($row) {
  10. $grid = new Grid(...);
  11. ...
  12. $row->column(12, $grid);
  13. });
  14. }
  15. }

AdminController

通过上面页面布局的相关内容的学习,我们明白了Dcat Admin的页面组成构建的方法,那么一个增删改查功能究竟是怎么实现的呢?我们可以看到一个由代码生成器生成的增删改查控制器代码大概如下所示

  1. use App\Admin\Repositories\User;
  2. use Dcat\Admin\Form;
  3. use Dcat\Admin\Grid;
  4. use Dcat\Admin\Show;
  5. use Dcat\Admin\Controllers\AdminController;
  6. class UserController extends AdminController
  7. {
  8. // 数据表格
  9. protected function grid()
  10. {
  11. return Grid::make(new User(), function (Grid $grid) {
  12. ...
  13. });
  14. }
  15. // 数据详情
  16. protected function detail($id)
  17. {
  18. return Show::make($id, new User(), function (Show $show) {
  19. ...
  20. });
  21. }
  22. // 表单
  23. protected function form()
  24. {
  25. return Form::make(new User(), function (Form $form) {
  26. ...
  27. });
  28. }
  29. }

上面的代码主要包含了griddetailform,从这些代码中,我们并没有办法改变一个页面的布局,那这个页面究竟是怎么构建的?我们又如何更改页面的布局?我们不妨打开AdminController看一看

  1. <?php
  2. namespace Dcat\Admin\Controllers;
  3. use Dcat\Admin\IFrameGrid;
  4. use Dcat\Admin\Layout\Content;
  5. use Illuminate\Routing\Controller;
  6. class AdminController extends Controller
  7. {
  8. // 页面标题
  9. protected $title;
  10. // 页面描述信息
  11. protected $description = [
  12. // 'index' => 'Index',
  13. // 'show' => 'Show',
  14. // 'edit' => 'Edit',
  15. // 'create' => 'Create',
  16. ];
  17. // 返回页面标题
  18. protected function title()
  19. {
  20. return $this->title ?: admin_trans_label();
  21. }
  22. // 返回描述信息
  23. protected function description()
  24. {
  25. return $this->description;
  26. }
  27. // 列表页
  28. public function index(Content $content)
  29. {
  30. if (request(IFrameGrid::QUERY_NAME)) {
  31. return $content->perfectScrollbar()->body($this->iFrameGrid());
  32. }
  33. return $content
  34. ->title($this->title())
  35. ->description($this->description()['index'] ?? trans('admin.list'))
  36. ->body($this->grid());
  37. }
  38. // 详情页
  39. public function show($id, Content $content)
  40. {
  41. return $content
  42. ->title($this->title())
  43. ->description($this->description()['show'] ?? trans('admin.show'))
  44. ->body($this->detail($id));
  45. }
  46. // 编辑页
  47. public function edit($id, Content $content)
  48. {
  49. return $content
  50. ->title($this->title())
  51. ->description($this->description()['edit'] ?? trans('admin.edit'))
  52. ->body($this->form()->edit($id));
  53. }
  54. // 新增页
  55. public function create(Content $content)
  56. {
  57. return $content
  58. ->title($this->title())
  59. ->description($this->description()['create'] ?? trans('admin.create'))
  60. ->body($this->form());
  61. }
  62. // 修改接口
  63. public function update($id)
  64. {
  65. return $this->form()->update($id);
  66. }
  67. // 新增接口
  68. public function store()
  69. {
  70. return $this->form()->store();
  71. }
  72. // 删除/批量删除接口
  73. public function destroy($id)
  74. {
  75. return $this->form()->destroy($id);
  76. }
  77. }

现在是不是就可以明白整个页面的组成部分了呢?其实系统内很多代码都是见名知意、简单易懂的,很多时候我们只需要通过阅读代码就可以知道用法。 例如我们要更改页面标题,通过阅读这段代码,就可以得知可以通过重写title方法或更改翻译文件的方式实现,是不是非常简单?

下面我们通过实现一个数据表格 + 数据统计卡片的列表页面,来演示一下更改页面布局的实际应用

  1. use App\Admin\Metrics\Examples\NewDevices;
  2. use App\Admin\Metrics\Examples\NewUsers;
  3. use App\Admin\Metrics\Examples\TotalUsers;
  4. use Dcat\Admin\Layout\Content;
  5. use Dcat\Admin\Layout\Row;
  6. public function index(Content $content)
  7. {
  8. if (request(IFrameGrid::QUERY_NAME)) {
  9. return $content->perfectScrollbar()->body($this->iFrameGrid());
  10. }
  11. return $content
  12. ->title($this->title())
  13. ->description($this->description()['index'] ?? trans('admin.list'))
  14. ->body(function (Row $row) {
  15. $row->column(4, new TotalUsers());
  16. $row->column(4, new NewUsers());
  17. $row->column(4, new NewDevices());
  18. })
  19. ->body($this->grid());
  20. }

实现效果如下

开发前必读 - 图1

Bootstrap4公共样式

Dcat Admin采用bootstrap4的栅格系统对页面进行布局,即简单又强大,开始开发前需要对此有所了解,另外bootsrap4提供了非常多非常有用的公共样式,对编写页面组件非常有帮助,能显著提高开发效率,建议编写组件前先查阅一遍文档,以下是推荐学习的样式列表:

  • 栅格布局
  • Display显示属性 通过我们的显示实用程序,可以快速、有效地切换组件的显示值和更多,包括对一些更常见的值的支持,此样式列表对响应式布局非常有帮助。
  • flex弹性布局 引入新的Flex弹性布局,可以实现通过一整套响应灵活的实用程序,快速管理栅格的列、导航、组件等的布局、对齐和大小。通过进一度的定义CSS,还可以实现更复杂的展示样式。
  • 颜色(Color) 通过颜色传达意义、表达不同的模块,这有一系列的定义方法,包括支持链接、悬停、选中等状态相关的的样式集。
  • Float浮动属性 使用我们的响应式float浮动通用样式,能在任何设备断点(浏览器尺寸)上切换浮动。
  • 规格(sizi) 使用系统宽度和高度样式,轻松地定义任何元素的宽或高(相对于其父级)
  • 间隔(spacing) 内置了各种的快速缩进、隔离、填充等间距处理工具,响应余量和填充实用程序类来修改元素的外观。
  • 文本处理 用于控制文本的对齐、组合、字重等示例以及使用文档。
  • 垂直对齐(vertical align) 轻松更改内联、内嵌块、内联表和表格单元格元素的垂直对齐方式。

内置样式

除了前面提到的bootstrap4公共样式,系统还内置了以下常用样式:

颜色

请参考颜色表样式

阴影

.shadow
.shadow-100
.shadow-200