arrilot / laravel-widgets
视图构建器的强大替代品。异步小部件、可重载小部件、控制台生成器、缓存——你能想到的一切。
Requires
- php: >=7.4
- illuminate/cache: >=9
- illuminate/console: >=9
- illuminate/container: >=9
- illuminate/contracts: >=9
- illuminate/routing: >=9
- illuminate/support: >=9
- illuminate/view: >=9
Requires (Dev)
- nunomaduro/larastan: ^2.6
- phpunit/phpunit: ~8.0
- dev-master
- 3.14.0
- 3.13.2
- 3.13.1
- 3.13.0
- 3.12
- 3.11.0
- 3.10.0
- 3.9.0
- 3.8.1
- 3.8.0
- 3.7.7
- 3.7.6
- 3.7.5
- 3.7.4
- 3.7.3
- 3.7.2
- 3.7.1
- 3.7.0
- 3.6.1
- 3.6.0
- 3.5.0
- 3.4.2
- 3.4.1
- 3.4.0
- 3.3.2
- 3.3.1
- 3.3.0
- 3.2.1
- 3.2.0
- 3.1.3
- 3.1.2
- 3.1.1
- 3.0.2
- 3.0.1
- 3.0.0
- 2.8.0
- 2.7
- 2.6
- 2.5.1
- 2.5.0
- 2.4.1
- 2.4.0
- 2.3.8
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.0.x-dev
- 1.0.2
- 1.0.1
- 1.0.0
- 0.2.3
- 0.2.2
- 0.2.1
- 0.2.0
- 0.1.2
- 0.1.1
- 0.1.0
- dev-php8-2-deprecation-error
- dev-scrutinizer-patch-1
This package is auto-updated.
Last update: 2024-09-19 20:08:24 UTC
README
Laravel小部件
视图构建器的强大替代品。异步小部件、可重载小部件、控制台生成器、缓存——你能想象的一切。
安装
运行composer require arrilot/laravel-widgets
使用方法
让我们假设我们想要创建一个最近新闻列表,并在多个视图中重用它。
首先,我们可以使用包提供的 artisan 命令创建一个 Widget 类。
php artisan make:widget RecentNews
该命令生成两个文件
resources/views/widgets/recent_news.blade.php
是一个空视图。
如果你不需要视图,可以添加“--plain”选项。
app/Widgets/RecentNews
是一个小部件类。
<?php namespace App\Widgets; use Arrilot\Widgets\AbstractWidget; class RecentNews extends AbstractWidget { /** * The configuration array. * * @var array */ protected array $config = []; /** * Treat this method as a controller action. * Return view() or other content to display. */ public function run() { // return view('widgets.recent_news', [ 'config' => $this->config, ]); } }
注意:如果你需要,可以使用自己的模板。发布配置文件以更改路径。
最后一步是调用小部件。有几种方法可以这样做。
@widget('recentNews')
或者
{{ Widget::run('recentNews') }}
甚至
{{ Widget::recentNews() }}
这些之间没有真正的区别。选择取决于你。
向小部件传递变量
通过配置数组
让我们继续使用“最近新闻”的例子。
假设我们通常需要显示五条新闻,但在某些视图中我们需要显示十条。这可以很容易地通过以下方式实现:
class RecentNews extends AbstractWidget { ... protected array $config = [ 'count' => 5 ]; ... } ... @widget('recentNews') // shows 5 @widget('recentNews', ['count' => 10]) // shows 10
['count' => 10]
是一个配置数组,可以通过 $this->config 访问。
配置数组在每个小部件方法中都是可用的,因此您可以使用它来配置占位符和容器(见下文)
注意:当你调用小部件时未指定的配置字段不会被覆盖
class RecentNews extends AbstractWidget { ... protected array $config = [ 'count' => 5, 'foo' => 'bar' ]; ... } @widget('recentNews', ['count' => 10]) // $this->config['foo'] is still 'bar'
注意2:你可能(可能不需要)创建自己的 BaseWidget 并从它继承。这是可以的。唯一的情况是从父类和子类合并配置默认值。在这种情况下,请按照以下操作:
-
不要向子类中添加
protected $config = [...]
行。 -
相反,添加默认值如下
public function __construct(array $config = []) { $this->addConfigDefaults([ 'child_key' => 'bar' ]); parent::__construct($config); }
直接(仅适用于Laravel版本低于7)
你也可以选择直接向run()
方法传递额外的参数。
@widget('recentNews', ['count' => 10], 'date', 'asc') ... public function run($sortBy, $sortOrder) { } ...
run()
方法是通过服务容器解析的,所以这里也可以使用方法注入。
命名空间
默认情况下,该包尝试在App\Widgets
命名空间中找到你的小部件。
你可以通过发布包配置(php artisan vendor:publish --provider="Arrilot\Widgets\ServiceProvider"
)并设置default_namespace
属性来覆盖此设置。
尽管使用默认命名空间非常方便,但在某些情况下,你可能希望有更多的灵活性。例如,如果你有成百上千个小部件,将它们分组在命名空间文件夹中是有意义的。
没问题,有几种方法可以调用这些小部件
- 将来自
default_namespace
(基本上是App\Widgets
)的完整小部件名称传递给run
方法。
@widget('News\RecentNews', $config)
- 使用点表示法。
@widget('news.recentNews', $config)
- 完全限定名(FQCN)也是可选的。
@widget('\App\Http\Some\Namespace\Widget', $config)
异步小部件
有时,用AJAX加载小部件内容可能非常有用。
幸运的是,这可以非常容易地实现!你所需要做的就是更改外观或blade指令 - Widget::
> AsyncWidget::
,@widget
> @asyncWidget
小部件参数默认情况下被加密,并通过ajax调用的底层发送。所以请期待它们在之后被json_encoded()
和json_decoded()
。
注意:您可以通过在它上面设置
public $encryptParams = false;
来关闭特定小部件的加密。然而,这个操作会使小部件参数公开可访问,所以请确保不要留下任何漏洞。例如,如果您通过小部件参数传递类似 user_id 的内容并关闭加密,您确实需要在小部件内添加一个额外的访问检查。
注意:您可以在配置文件中将
use_jquery_for_ajax_calls
设置为true
,以便在需要时将其用于 AJAX 调用,但在此情况下您需要手动将 jQuery 添加到您的页面上。
默认情况下,直到 AJAX 调用完成之前不会显示任何内容。
您可以通过向小部件类添加一个 placeholder()
方法来自定义此内容。
public function placeholder(): string { return 'Loading...'; }
侧注:如果您需要使用用于加载异步小部件的路由包进行某些操作(例如,您在子目录中运行应用程序 http://site.com/app/),您需要将 Arrilot\Widgets\ServiceProvider 复制到您的应用程序中,根据您的需要进行修改,并在 Laravel 中注册它,而不是使用前者。
可重载小部件
您可以更进一步,自动每 N 秒重载一次小部件。
只需设置小部件类的 $reloadTimeout
属性即可。
class RecentNews extends AbstractWidget { /** * The number of seconds before each reload. * * @var int|float */ public $reloadTimeout = 10; }
同步和异步小部件都可以成为可重载的。
您应该谨慎使用此功能,因为如果超时时间太短,它很容易用 AJAX 调用垃圾邮件骚扰您的应用程序。考虑使用 WebSockets,但它们设置起来要复杂得多。
容器
异步和可重载的小部件都需要一些 DOM 交互,因此它们将所有小部件输出包裹在一个 HTML 容器中。此容器由 AbstractWidget::container()
方法定义,也可以进行自定义。
/** * Async and reloadable widgets are wrapped in container. * You can customize it by overriding this method. * * @return array */ public function container(): array { return [ 'element' => 'div', 'attributes' => 'style="display:inline" class="arrilot-widget-container"', ]; }
注意:不支持嵌套异步或可重载的小部件。
缓存
还有一种简单的方法可以缓存整个小部件输出。只需在您的小部件类中设置 $cacheTime 属性即可。
class RecentNews extends AbstractWidget { /** * The number of minutes before cache expires. * False means no caching at all. * * @var int|float|bool */ public $cacheTime = 60; }
默认情况下不启用缓存。缓存键取决于小部件名称和每个小部件参数。如果需要调整它,请重写 cacheKey
方法。
缓存标签
当支持标签时(见 Laravel 缓存文档)以及为了简化缓存刷新,默认情况下将标签 widgets
分配给所有小部件。您可以通过在您的小部件类中设置 $cacheTags
属性来为小部件定义一个或多个附加标签。例如
class RecentNews extends AbstractWidget { /** * Cache tags allow you to tag related items in the cache * and then flush all cached values that assigned a given tag. * * @var array */ public array $cacheTags = ['news', 'frontend']; }
对于这个例子,如果您需要刷新
// Clear widgets with the tag news Cache::tags('news')->flush(); // Clear widgets with the tag news OR backend Cache::tags(['news', 'frontend'])->flush(); // Flush all widgets cache Cache::tags('widgets')->flush();
小部件组(额外功能)
在大多数情况下,Blade 是设置小部件位置和顺序的完美工具。然而,有时您可能会发现以下方法很有用
// add several widgets to the 'sidebar' group anywhere you want (even in controller) Widget::group('sidebar')->position(5)->addWidget('widgetName1', $config1); Widget::group('sidebar')->position(4)->addAsyncWidget('widgetName2', $config2); // display them in a view in the correct order @widgetGroup('sidebar') // or {{ Widget::group('sidebar')->display() }}
可以省略链中的 position()
。
Widget::group('sidebar')->addWidget('files');
等价于
Widget::group('sidebar')->position(100)->addWidget('files');
您可以为组中的小部件之间显示的分隔符设置一个。 Widget::group('sidebar')->setSeparator('<hr>')->...;
您还可以使用 wrap
方法将每个组中的小部件包裹起来。
Widget::group('sidebar')->wrap(function ($content, $index, $total) { // $total is a total number of widgets in a group. return "<div class='widget-{$index}'>{$content}</div>"; })->...;
从组中删除小部件
有几种方法可以在小部件被添加后从组中删除小部件。
- 通过其唯一的
id
删除一个小部件
$id1 = Widget::group('sidebar')->addWidget('files'); $id2 = Widget::group('sidebar')->addAsyncWidget('files'); Widget::group('sidebar')->removeById($id1); // There is only second widget in the group now
- 删除具有特定名称的所有小部件
Widget::group('sidebar')->addWidget('files'); Widget::group('sidebar')->addAsyncWidget('files'); Widget::group('sidebar')->removeByName('files'); // Widget group is empty now
- 删除放置在特定位置的所有小部件
Widget::group('sidebar')->position(42)->addWidget('files'); Widget::group('sidebar')->position(42)->addAsyncWidget('files'); Widget::group('sidebar')->removeByPosition(42); // Widget group is empty now
- 一次性删除所有小部件。
Widget::group('sidebar')->addWidget('files'); Widget::group('sidebar')->addAsyncWidget('files'); Widget::group('sidebar')->removeAll(); // Widget group is empty now
检查组的状态
Widget::group('sidebar')->isEmpty(); // 布尔值
Widget::group('sidebar')->any(); // 布尔值
Widget::group('sidebar')->count(); // 整数
第三方包的命名空间(额外功能)
在某些情况下,将小部件与您自己的包一起提供可能很有用。例如,如果您的包允许您管理新闻,那么将立即可配置的小部件直接随包提供,以便直接显示,将非常方便。
为了避免每次都使用完全限定类名(fqcn),您可以在您的包提供者中设置一个小部件命名空间。这样,您包中的小部件可以更容易地被识别,特别是语法会更短。
要做到这一点,您只需要在您的包服务提供者中注册命名空间。
public function boot() { app('arrilot.widget-namespaces')->registerNamespace('my-package-name', '\VendorName\PackageName\Path\To\Widgets'); }
之后,您就可以在视图中使用该命名空间。
@widget('my-package-name::foo.bar') // is equivalent to @widget('\VendorName\PackageName\Path\To\Widgets\Foo\Bar')