异步加载基本使用

{tip} Since v1.7.0 异步加载功能支持静态资源按需加载的特性,目前内置的所有组件都支持使用异步渲染功能,并且支持在页面的任意位置中使用

通过异步加载功能可以让页面中的整体或局部组件使用ajax异步渲染,从而提高页面加载效率(例如弹窗异步加载表单)。

基本用法

下面通过一个简单的示例来演示异步加载功能的用法

先定义一个异步渲染类,继承Dcat\Admin\Support\LazyRenderable

  1. <?php
  2. namespace App\Admin\Renderable;
  3. use App\Admin\Widgets\Charts\Bar;
  4. use Dcat\Admin\Support\LazyRenderable;
  5. class PostChart extends LazyRenderable
  6. {
  7. public function render()
  8. {
  9. // 获取外部传递的参数
  10. $id = $this->id;
  11. // 查询数据逻辑
  12. $data = [...];
  13. // 这里可以返回内置组件,也可以返回视图文件或HTML字符串
  14. return Bar::make($data);
  15. }
  16. }

然后需要把渲染类实例传入Dcat\Admin\Widgets\Lazy对象中,才能最终实现异步渲染的效果

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. // 实例化异步渲染类并传递自定义参数
  7. $chart = PostChart::make(['id' => ...]);
  8. return $content->body(Lazy::make($chart));
  9. }

也可以放在内置组件中

{tip} 如果是 Dcat\Admin\Widgets\CardDcat\Admin\Widgets\BoxDcat\Admin\Widgets\ModalDcat\Admin\Widgets\Tab等组件,则可以略过Dcat\Admin\Widgets\Lazy组件,直接传递渲染类实例

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Card;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. $chart = PostChart::make(['id' => ...]);
  7. // Card 组件支持直接传递 LazyRenderable 实例,可以略过 Lazy 对象
  8. return $content->body(Card::make($chart));
  9. }
  10. // 如果是 Modal、Box 等等都可以直接略过 Lazy
  11. use Dcat\Admin\Widgets\Modal;
  12. $chart = PostChart::make(['id' => ...]);
  13. $modal = Modal::make()
  14. ->lg()
  15. ->title('标题')
  16. ->delay(300) // 如果是异步渲染图表则需要设置一个延迟时间,否则可能导致图表渲染异常
  17. ->body($chart);

当然也可以防止在视图或者是HTML代码中

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. $chart = Lazy::make(PostChart::make(['id' => ...]));
  7. return $content->body(view('admin.xxx', ['chart' => $chart]));
  8. }

效果

异步加载基本使用 - 图1

Dcat\Admin\Support\LazyRenderable

参数传递 (payload)

  1. use App\Admin\Renderable\PostChart;
  2. PostChart::make(['key1' => '值', ...]);
  3. // 也可以通过 payload 方法传递
  4. PostChart::make()->payload(['key1' => '值', ...]);

获取参数

  1. class PostChart extends LazyRenderable
  2. {
  3. protected $title = ['#', '标题', '内容'];
  4. public function render()
  5. {
  6. // 获取外部传递的参数
  7. $key1 = $this->key1;
  8. $key2 = $this->key2;
  9. ...
  10. }
  11. }

载入JS和CSS

异步加载功能同样支持静态资源按需加载的特性,并且用法也很简单

  1. <?php
  2. namespace App\Admin\Renderable;
  3. use Dcat\Admin\Support\LazyRenderable;
  4. use Dcat\Admin\Admin;
  5. class CustomView extends LazyRenderable
  6. {
  7. // 这里写入需要加载的js和css文件路径
  8. public static $js = [
  9. 'xxx/xxx1.js',
  10. 'xxx/xxx2.js',
  11. ];
  12. public static $css = [
  13. 'xxx/xxx1.css',
  14. 'xxx/xxx2.css',
  15. ];
  16. protected function addScript()
  17. {
  18. Admin::script(
  19. <<<JS
  20. console.log('JS脚本都加载完了~');
  21. JS
  22. );
  23. }
  24. public function render()
  25. {
  26. // 添加你的 JS 代码
  27. $this->addScript();
  28. return view('admin.custom', ['...']);
  29. }
  30. }

模板文件代码示例,注意不要包含bodyhtml等标签

  1. <div id="custom" class="custom"><h2>异步加载功能</h2></div>
  2. <script>
  3. Dcat.ready(function () {
  4. // JS 代码也可以放在模板文件中
  5. console.log('模板文件执行js~');
  6. });
  7. </script>

Dcat\Admin\Widgets\Lazy

onLoad

通过此方法可以监听异步加载完成事件

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. $chart = Lazy::make(PostChart::make())->onLoad(
  4. <<<JS
  5. console.log('组件渲染完成');
  6. JS
  7. );

load

此方法可以控制是否立即渲染异步组件,默认值是true

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. use Dcat\Admin\Admin;
  4. $lazy = Lazy::make(PostChart::make())->load(false);
  5. Admin::script(
  6. <<<JS
  7. setTimeout(function () {
  8. // 3秒后自动触发异步渲染事件
  9. {$lazy->getLoadScript()}
  10. }, 3000);
  11. JS
  12. );

JS事件

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. use Dcat\Admin\Admin;
  4. $lazy = Lazy::make(PostChart::make());
  5. Admin::script(
  6. <<<JS
  7. // 手动触发异步渲染事件
  8. $('{$lazy->getElementSelector()}').trigger('lazy:load');
  9. // 监听渲染完成事件
  10. $('{$lazy->getElementSelector()}').on('lazy:loaded', function () {
  11. console.log('组件渲染完成了')
  12. });
  13. JS
  14. );

异步加载数据表格

如果需要异步异步加载数据表格,则定义渲染类时需要继承Dcat\Admin\Grid\LazyRenderable

  1. <?php
  2. namespace App\Admin\Renderable;
  3. use Dcat\Admin\Grid;
  4. use Dcat\Admin\Grid\LazyRenderable;
  5. use Dcat\Admin\Models\Administrator;
  6. class UserTable extends LazyRenderable
  7. {
  8. public function grid(): Grid
  9. {
  10. return Grid::make(new Administrator(), function (Grid $grid) {
  11. $grid->column('id');
  12. $grid->column('username');
  13. $grid->column('name');
  14. $grid->column('created_at');
  15. $grid->column('updated_at');
  16. $grid->quickSearch(['id', 'username', 'name']);
  17. $grid->paginate(10);
  18. $grid->disableActions();
  19. $grid->filter(function (Grid\Filter $filter) {
  20. $filter->like('username')->width(4);
  21. $filter->like('name')->width(4);
  22. });
  23. });
  24. }
  25. }

使用

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\Modal;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. $modal = Modal::make()
  7. ->lg()
  8. ->title('异步加载 - 表格')
  9. ->body(UserTable::make()) // Modal 组件支持直接传递 渲染类实例
  10. ->button('打开表格');
  11. return $content->body($modal);
  12. }

效果

异步加载基本使用 - 图2

同样渲染类的实例也可以附加到 Dcat\Admin\Widgets\CardDcat\Admin\Widgets\BoxDcat\Admin\Widgets\Tab等组件中

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\Card;
  3. $table = UserTable::make();
  4. $card = Card::make('标题', $table)->withHeaderBorder();

以上代码渲染UserTable实例时,其实是底层自动加上了Dcat\Admin\Widgets\LazyTable类实例,以上代码等同于

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\Card;
  3. use Dcat\Admin\Widgets\LazyTable;
  4. $table = LazyTable::make(UserTable::make()->simple());
  5. $card = Card::make('标题', $table)->withHeaderBorder();

Dcat\Admin\Grid\LazyRenderable

Dcat\Admin\Grid\LazyRenderable用于异步渲染数据表格,是Dcat\Admin\Support\LazyRenderable的子类

简化模式

此功能会去除简化一些数据表格默认开启的功能,默认不启用

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\LazyTable;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. $table = UserTable::make()->simple();
  7. return $content->body(LazyTable::make($table));
  8. }

注意,如果把渲染类实例直接注入到Dcat\Admin\Widgets\CardDcat\Admin\Widgets\BoxDcat\Admin\Widgets\TabDcat\Admin\Widgets\Modal等组件时,则会自动启用simple模式

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\Card;
  3. // 这里会自动启用 simple 模式
  4. $card = Card::make('标题', UserTable::make())->withHeaderBorder();

如果你不希望启用 simple 模式,可以传入 LazyTable 实例

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\Card;
  3. use Dcat\Admin\Widgets\LazyTable;
  4. $table = LazyTable::make(UserTable::make());
  5. $card = Card::make('标题', $table)->withHeaderBorder();

Dcat\Admin\Widgets\LazyTable

onLoad

通过此方法可以监听异步加载完成事件

  1. use App\Admin\Renderable\PostChart;
  2. use Dcat\Admin\Widgets\Lazy;
  3. $chart = Lazy::make(PostChart::make())->onLoad(
  4. <<<JS
  5. console.log('组件渲染完成');
  6. JS
  7. );

load

此方法可以控制是否立即渲染异步组件,默认值是true

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\LazyTable;
  3. use Dcat\Admin\Admin;
  4. $lazy = LazyTable::make(UserTable::make())->load(false);
  5. Admin::script(
  6. <<<JS
  7. setTimeout(function () {
  8. // 3秒后自动触发异步渲染事件
  9. {$lazy->getLoadScript()}
  10. }, 3000);
  11. JS
  12. );

JS事件

  1. use App\Admin\Renderable\UserTable;
  2. use Dcat\Admin\Widgets\LazyTable;
  3. use Dcat\Admin\Admin;
  4. $lazy = LazyTable::make(UserTable::make());
  5. Admin::script(
  6. <<<JS
  7. // 手动触发异步渲染事件
  8. $('{$lazy->getElementSelector()}').trigger('table:load');
  9. // 监听渲染完成事件
  10. $('{$lazy->getElementSelector()}').on('table:loaded', function () {
  11. console.log('组件渲染完成了')
  12. });
  13. JS
  14. );

异步加载工具表单

定义工具表单类,实现Dcat\Admin\Contracts\LazyRenderable,并载入Dcat\Admin\Traits\LazyWidget这个trait

  1. <?php
  2. namespace App\Admin\Forms;
  3. use Dcat\Admin\Contracts\LazyRenderable;
  4. use Dcat\Admin\Traits\LazyWidget;
  5. use Dcat\Admin\Widgets\Form;
  6. class UserProfile extends Form implements LazyRenderable
  7. {
  8. use LazyWidget;
  9. public function handle(array $input)
  10. {
  11. return $this->success('保存成功');
  12. }
  13. public function form()
  14. {
  15. $this->text('name', trans('admin.name'))->required()->help('用户昵称');
  16. $this->image('avatar', trans('admin.avatar'))->autoUpload();
  17. $this->password('old_password', trans('admin.old_password'));
  18. $this->password('password', trans('admin.password'))
  19. ->minLength(5)
  20. ->maxLength(20)
  21. ->customFormat(function ($v) {
  22. if ($v == $this->password) {
  23. return;
  24. }
  25. return $v;
  26. })
  27. ->help('请输入5-20个字符');
  28. $this->password('password_confirmation', trans('admin.password_confirmation'))
  29. ->same('password')
  30. ->help('请输入确认密码');
  31. }
  32. }

使用

  1. use App\Admin\Forms\UserProfile;
  2. use Dcat\Admin\Widgets\Modal;
  3. use Dcat\Admin\Layout\Content;
  4. public function index(Content $content)
  5. {
  6. $modal = Modal::make()
  7. ->lg()
  8. ->title('异步加载 - 表单')
  9. ->body(UserProfile::make()) // Modal 组件支持直接传递渲染类实例
  10. ->button('打开表单');
  11. return $content->body($modal);
  12. }

效果

异步加载基本使用 - 图3

当然异步表单实例,也可以在其他组件中使用

  1. use App\Admin\Forms\UserProfile;
  2. use Dcat\Admin\Widgets\Lazy;
  3. use Dcat\Admin\Widgets\Card;
  4. $form = UserProfile::make();
  5. // 直接传递到 Card 组件中
  6. $card = Card::make($form);
  7. // 等同于
  8. $card = Card::make(Lazy::make($form));

传递自定义参数

给异步表单传递参数非常简单,修改上面表单类如下

  1. <?php
  2. namespace App\Admin\Forms;
  3. use Dcat\Admin\Contracts\LazyRenderable;
  4. use Dcat\Admin\Traits\LazyWidget;
  5. use Dcat\Admin\Widgets\Form;
  6. class UserProfile extends Form implements LazyRenderable
  7. {
  8. use LazyWidget;
  9. public function handle(array $input)
  10. {
  11. // 获取外部传递的参数
  12. $key1 = $this->payload['key1'] ?? null;
  13. $key2 = $this->payload['key1'] ?? null;
  14. return $this->success('保存成功');
  15. }
  16. public function form()
  17. {
  18. // 获取外部传递的参数
  19. $key1 = $this->payload['key1'] ?? null;
  20. $key2 = $this->payload['key1'] ?? null;
  21. $this->text('name', trans('admin.name'))->required()->help('用户昵称');
  22. $this->image('avatar', trans('admin.avatar'))->autoUpload();
  23. $this->password('old_password', trans('admin.old_password'));
  24. $this->password('password', trans('admin.password'))
  25. ->minLength(5)
  26. ->maxLength(20)
  27. ->customFormat(function ($v) {
  28. if ($v == $this->password) {
  29. return;
  30. }
  31. return $v;
  32. })
  33. ->help('请输入5-20个字符');
  34. $this->password('password_confirmation', trans('admin.password_confirmation'))
  35. ->same('password')
  36. ->help('请输入确认密码');
  37. }
  38. public function default()
  39. {
  40. // 获取外部传递的参数
  41. $key1 = $this->payload['key1'] ?? null;
  42. $key2 = $this->payload['key1'] ?? null;
  43. return [
  44. 'name' => '...',
  45. ];
  46. }
  47. }

传递参数代码如下

  1. // 传递自定义参数
  2. $form = UserProfile::make()->payload(['key1' => '...', 'key2' => '...']);
  3. $modal = Modal::make()
  4. ->lg()
  5. ->title('异步加载 - 表单')
  6. ->body($form)
  7. ->button('打开表单');