异步加载基本使用
<h1>异步加载基本使用</h1>
<p>> {tip} 异步加载功能支持<strong>静态资源按需加载</strong>的特性,目前内置的<strong>所有组件</strong>都支持使用异步渲染功能,并且支持在页面的<strong>任意位置</strong>中使用</p>
<p>通过异步加载功能可以让页面中的整体或局部组件使用<code>ajax</code>异步渲染,从而提高页面加载效率(例如弹窗异步加载表单)。</p>
<h2>基本用法</h2>
<p>下面通过一个简单的示例来演示异步加载功能的用法</p>
<p>先定义一个异步渲染类,继承<code>Dcat\Admin\Support\LazyRenderable</code></p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Renderable;
use App\Admin\Widgets\Charts\Bar;
use Dcat\Admin\Support\LazyRenderable;
class PostChart extends LazyRenderable
{
public function render()
{
// 获取外部传递的参数
$id = $this-&gt;id;
// 查询数据逻辑
$data = [...];
// 这里可以返回内置组件,也可以返回视图文件或HTML字符串
return Bar::make($data);
}
}</code></pre>
<p>然后需要把渲染类实例传入<code>Dcat\Admin\Widgets\Lazy</code>对象中,才能最终实现异步渲染的效果</p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
// 实例化异步渲染类并传递自定义参数
$chart = PostChart::make(['id' =&gt; ...]);
return $content-&gt;body(Lazy::make($chart));
}</code></pre>
<p>也可以放在内置组件中</p>
<p>> {tip} 如果是 <code>Dcat\Admin\Widgets\Card</code>、<code>Dcat\Admin\Widgets\Box</code>、<code>Dcat\Admin\Widgets\Modal</code>、<code>Dcat\Admin\Widgets\Tab</code>等组件,则可以略过<code>Dcat\Admin\Widgets\Lazy</code>组件,直接传递渲染类实例</p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Card;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
$chart = PostChart::make(['id' =&gt; ...]);
// Card 组件支持直接传递 LazyRenderable 实例,可以略过 Lazy 对象
return $content-&gt;body(Card::make($chart));
}
// 如果是 Modal、Box 等等都可以直接略过 Lazy
use Dcat\Admin\Widgets\Modal;
$chart = PostChart::make(['id' =&gt; ...]);
$modal = Modal::make()
-&gt;lg()
-&gt;title('标题')
-&gt;delay(300) // 如果是异步渲染图表则需要设置一个延迟时间,否则可能导致图表渲染异常
-&gt;body($chart);</code></pre>
<p>当然也可以防止在视图或者是<code>HTML</code>代码中</p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
$chart = Lazy::make(PostChart::make(['id' =&gt; ...]));
return $content-&gt;body(view('admin.xxx', ['chart' =&gt; $chart]));
}</code></pre>
<p>效果</p>
<p><a href="<a href="https://cdn.learnku.com/uploads/images/202008/20/38389/Z1X46kZLtM.gif!large"">https://cdn.learnku.com/uploads/images/202008/20/38389/Z1X46kZLtM.gif!large"</a>; target="_blank">
<img src="https://cdn.learnku.com/uploads/images/202008/20/38389/Z1X46kZLtM.gif!large" alt="" />
</a></p>
<h3>Dcat\Admin\Support\LazyRenderable</h3>
<h4>参数传递 (payload)</h4>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
PostChart::make(['key1' =&gt; '值', ...]);
// 也可以通过 payload 方法传递
PostChart::make()-&gt;payload(['key1' =&gt; '值', ...]);</code></pre>
<p>获取参数</p>
<pre><code class="language-php">class PostChart extends LazyRenderable
{
protected $title = ['#', '标题', '内容'];
public function render()
{
// 获取外部传递的参数
$key1 = $this-&gt;key1;
$key2 = $this-&gt;key2;
...
}
}</code></pre>
<h4>载入JS和CSS</h4>
<p>异步加载功能同样支持<strong>静态资源按需加载</strong>的特性,并且用法也很简单</p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Renderable;
use Dcat\Admin\Support\LazyRenderable;
use Dcat\Admin\Admin;
class CustomView extends LazyRenderable
{
// 这里写入需要加载的js和css文件路径
public static $js = [
'xxx/xxx1.js',
'xxx/xxx2.js',
];
public static $css = [
'xxx/xxx1.css',
'xxx/xxx2.css',
];
protected function addScript()
{
Admin::script(
&lt;&lt;&lt;JS
console.log('JS脚本都加载完了~');
JS
);
}
public function render()
{
// 添加你的 JS 代码
$this-&gt;addScript();
return view('admin.custom', ['...']);
}
}</code></pre>
<p>模板文件代码示例,注意不要包含<code>body</code>和<code>html</code>等标签</p>
<pre><code class="language-HTML">&lt;div id=&quot;custom&quot; class=&quot;custom&quot;&gt;&lt;h2&gt;异步加载功能&lt;/h2&gt;&lt;/div&gt;
&lt;script&gt;
Dcat.ready(function () {
// JS 代码也可以放在模板文件中
console.log('模板文件执行js~');
});
&lt;/script&gt;</code></pre>
<h3>Dcat\Admin\Widgets\Lazy</h3>
<h4>onLoad</h4>
<p>通过此方法可以监听异步加载完成事件</p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
$chart = Lazy::make(PostChart::make())-&gt;onLoad(
&lt;&lt;&lt;JS
console.log('组件渲染完成');
JS
);</code></pre>
<h4>load</h4>
<p>此方法可以控制是否立即渲染异步组件,默认值是<code>true</code></p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
use Dcat\Admin\Admin;
$lazy = Lazy::make(PostChart::make())-&gt;load(false);
Admin::script(
&lt;&lt;&lt;JS
setTimeout(function () {
// 3秒后自动触发异步渲染事件
{$lazy-&gt;getLoadScript()}
}, 3000);
JS
);</code></pre>
<h4>JS事件</h4>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
use Dcat\Admin\Admin;
$lazy = Lazy::make(PostChart::make());
Admin::script(
&lt;&lt;&lt;JS
// 手动触发异步渲染事件
$('{$lazy-&gt;getElementSelector()}').trigger('lazy:load');
// 监听渲染完成事件
$('{$lazy-&gt;getElementSelector()}').on('lazy:loaded', function () {
console.log('组件渲染完成了')
});
JS
);</code></pre>
<p><a name="lazy-table"></a></p>
<h2>异步加载数据表格</h2>
<p>如果需要异步异步加载数据表格,则定义渲染类时需要继承<code>Dcat\Admin\Grid\LazyRenderable</code></p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Renderable;
use Dcat\Admin\Grid;
use Dcat\Admin\Grid\LazyRenderable;
use Dcat\Admin\Models\Administrator;
class UserTable extends LazyRenderable
{
// 指定翻译文件名称
protected $translation = 'user';
public function grid(): Grid
{
return Grid::make(new Administrator(), function (Grid $grid) {
$grid-&gt;column('id');
$grid-&gt;column('username');
$grid-&gt;column('name');
$grid-&gt;column('created_at');
$grid-&gt;column('updated_at');
$grid-&gt;quickSearch(['id', 'username', 'name']);
$grid-&gt;paginate(10);
$grid-&gt;disableActions();
$grid-&gt;filter(function (Grid\Filter $filter) {
$filter-&gt;like('username')-&gt;width(4);
$filter-&gt;like('name')-&gt;width(4);
});
});
}
}</code></pre>
<p>使用</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\Modal;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
$modal = Modal::make()
-&gt;lg()
-&gt;title('异步加载 - 表格')
-&gt;body(UserTable::make()) // Modal 组件支持直接传递 渲染类实例
-&gt;button('打开表格');
return $content-&gt;body($modal);
}</code></pre>
<p>效果</p>
<p><a href="<a href="https://cdn.learnku.com/uploads/images/202008/23/38389/HiAMIvKext.gif!large"">https://cdn.learnku.com/uploads/images/202008/23/38389/HiAMIvKext.gif!large"</a>; target="_blank">
<img src="https://cdn.learnku.com/uploads/images/202008/23/38389/HiAMIvKext.gif!large" alt="" />
</a></p>
<p>同样渲染类的实例也可以附加到 <code>Dcat\Admin\Widgets\Card</code>、<code>Dcat\Admin\Widgets\Box</code>、<code>Dcat\Admin\Widgets\Tab</code>等组件中</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\Card;
$table = UserTable::make();
$card = Card::make('标题', $table)-&gt;withHeaderBorder();</code></pre>
<p>以上代码渲染<code>UserTable</code>实例时,其实是底层自动加上了<code>Dcat\Admin\Widgets\LazyTable</code>类实例,以上代码等同于</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\Card;
use Dcat\Admin\Widgets\LazyTable;
$table = LazyTable::make(UserTable::make()-&gt;simple());
$card = Card::make('标题', $table)-&gt;withHeaderBorder();</code></pre>
<h3>Dcat\Admin\Grid\LazyRenderable</h3>
<p><code>Dcat\Admin\Grid\LazyRenderable</code>用于异步渲染数据表格,是<code>Dcat\Admin\Support\LazyRenderable</code>的子类</p>
<h4>简化模式</h4>
<p>此功能会去除简化一些数据表格默认开启的功能,默认不启用</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\LazyTable;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
$table = UserTable::make()-&gt;simple();
return $content-&gt;body(LazyTable::make($table));
}</code></pre>
<p>注意,如果把渲染类实例直接注入到<code>Dcat\Admin\Widgets\Card</code>、<code>Dcat\Admin\Widgets\Box</code>、<code>Dcat\Admin\Widgets\Tab</code>和<code>Dcat\Admin\Widgets\Modal</code>等组件时,则会自动启用<code>simple</code>模式</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\Card;
// 这里会自动启用 simple 模式
$card = Card::make('标题', UserTable::make())-&gt;withHeaderBorder();</code></pre>
<p>如果你不希望启用 simple 模式,可以传入 LazyTable 实例</p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\Card;
use Dcat\Admin\Widgets\LazyTable;
$table = LazyTable::make(UserTable::make());
$card = Card::make('标题', $table)-&gt;withHeaderBorder();</code></pre>
<h3>Dcat\Admin\Widgets\LazyTable</h3>
<h4>onLoad</h4>
<p>通过此方法可以监听异步加载完成事件</p>
<pre><code class="language-php">use App\Admin\Renderable\PostChart;
use Dcat\Admin\Widgets\Lazy;
$chart = Lazy::make(PostChart::make())-&gt;onLoad(
&lt;&lt;&lt;JS
console.log('组件渲染完成');
JS
);</code></pre>
<h4>load</h4>
<p>此方法可以控制是否立即渲染异步组件,默认值是<code>true</code></p>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\LazyTable;
use Dcat\Admin\Admin;
$lazy = LazyTable::make(UserTable::make())-&gt;load(false);
Admin::script(
&lt;&lt;&lt;JS
setTimeout(function () {
// 3秒后自动触发异步渲染事件
{$lazy-&gt;getLoadScript()}
}, 3000);
JS
);</code></pre>
<h4>JS事件</h4>
<pre><code class="language-php">use App\Admin\Renderable\UserTable;
use Dcat\Admin\Widgets\LazyTable;
use Dcat\Admin\Admin;
$lazy = LazyTable::make(UserTable::make());
Admin::script(
&lt;&lt;&lt;JS
// 手动触发异步渲染事件
$('{$lazy-&gt;getElementSelector()}').trigger('table:load');
// 监听渲染完成事件
$('{$lazy-&gt;getElementSelector()}').on('table:loaded', function () {
console.log('组件渲染完成了')
});
JS
);</code></pre>
<p><a name="lazy-form"></a></p>
<h2>异步加载工具表单</h2>
<p>定义工具表单类,实现<code>Dcat\Admin\Contracts\LazyRenderable</code>,并载入<code>Dcat\Admin\Traits\LazyWidget</code>这个<code>trait</code></p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Forms;
use Dcat\Admin\Contracts\LazyRenderable;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
class UserProfile extends Form implements LazyRenderable
{
use LazyWidget;
// 指定翻译文件名称
protected $translation = 'user-profile';
public function handle(array $input)
{
return $this-&gt;response()-&gt;success('保存成功');
}
public function form()
{
$this-&gt;text('name', trans('admin.name'))-&gt;required()-&gt;help('用户昵称');
$this-&gt;image('avatar', trans('admin.avatar'))-&gt;autoUpload();
$this-&gt;password('old_password', trans('admin.old_password'));
$this-&gt;password('password', trans('admin.password'))
-&gt;minLength(5)
-&gt;maxLength(20)
-&gt;customFormat(function ($v) {
if ($v == $this-&gt;password) {
return;
}
return $v;
})
-&gt;help('请输入5-20个字符');
$this-&gt;password('password_confirmation', trans('admin.password_confirmation'))
-&gt;same('password')
-&gt;help('请输入确认密码');
}
}</code></pre>
<p>使用</p>
<pre><code class="language-php">use App\Admin\Forms\UserProfile;
use Dcat\Admin\Widgets\Modal;
use Dcat\Admin\Layout\Content;
public function index(Content $content)
{
$modal = Modal::make()
-&gt;lg()
-&gt;title('异步加载 - 表单')
-&gt;body(UserProfile::make()) // Modal 组件支持直接传递渲染类实例
-&gt;button('打开表单');
return $content-&gt;body($modal);
}</code></pre>
<p>效果</p>
<p><img src="https://cdn.learnku.com/uploads/images/202008/20/38389/C8InwPTsQG.gif!large" alt="" /></p>
<p>当然异步表单实例,也可以在其他组件中使用</p>
<pre><code class="language-php">use App\Admin\Forms\UserProfile;
use Dcat\Admin\Widgets\Lazy;
use Dcat\Admin\Widgets\Card;
$form = UserProfile::make();
// 直接传递到 Card 组件中
$card = Card::make($form);
// 等同于
$card = Card::make(Lazy::make($form));</code></pre>
<h3>传递自定义参数</h3>
<p>给异步表单传递参数非常简单,修改上面表单类如下</p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Forms;
use Dcat\Admin\Contracts\LazyRenderable;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;
class UserProfile extends Form implements LazyRenderable
{
use LazyWidget;
public function handle(array $input)
{
// 获取外部传递的参数
$key1 = $this-&gt;payload['key1'] ?? null;
$key2 = $this-&gt;payload['key1'] ?? null;
return $this-&gt;response()-&gt;success('保存成功');
}
public function form()
{
// 获取外部传递的参数
$key1 = $this-&gt;payload['key1'] ?? null;
$key2 = $this-&gt;payload['key1'] ?? null;
$this-&gt;text('name', trans('admin.name'))-&gt;required()-&gt;help('用户昵称');
$this-&gt;image('avatar', trans('admin.avatar'))-&gt;autoUpload();
$this-&gt;password('old_password', trans('admin.old_password'));
$this-&gt;password('password', trans('admin.password'))
-&gt;minLength(5)
-&gt;maxLength(20)
-&gt;customFormat(function ($v) {
if ($v == $this-&gt;password) {
return;
}
return $v;
})
-&gt;help('请输入5-20个字符');
$this-&gt;password('password_confirmation', trans('admin.password_confirmation'))
-&gt;same('password')
-&gt;help('请输入确认密码');
}
public function default()
{
// 获取外部传递的参数
$key1 = $this-&gt;payload['key1'] ?? null;
$key2 = $this-&gt;payload['key1'] ?? null;
return [
'name' =&gt; '...',
];
}
}</code></pre>
<p>传递参数代码如下</p>
<pre><code class="language-php">// 传递自定义参数
$form = UserProfile::make()-&gt;payload(['key1' =&gt; '...', 'key2' =&gt; '...']);
$modal = Modal::make()
-&gt;lg()
-&gt;title('异步加载 - 表单')
-&gt;body($form)
-&gt;button('打开表单');</code></pre>