Skip to content
全部文档

在 Livewire 组件中渲染操作

WARNING

继续之前,请确认项目中已安装 filament/actions。可通过运行以下命令检查:

bash
composer show filament/actions

若尚未安装,请参阅安装指南,并按说明配置独立组件

设置 Livewire 组件

首先,生成一个新的 Livewire 组件:

bash
php artisan make:livewire ManagePost

然后,在页面上渲染该 Livewire 组件:

blade
@livewire('manage-post')

或者,你也可以使用整页 Livewire 组件:

php
use App\Livewire\ManagePost;
use Illuminate\Support\Facades\Route;

Route::get('posts/{post}/manage', ManagePost::class);

你必须在 Livewire 组件类上使用 InteractsWithActionsInteractsWithSchemas trait,并实现 HasActionsHasSchemas 接口:

php
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Concerns\RestrictsFileUploadsToSchemaComponents;
use Filament\Schemas\Contracts\HasSchemas;
use Livewire\Component;

class ManagePost extends Component implements HasActions, HasSchemas
{
    use InteractsWithActions;
    use InteractsWithSchemas;
    use RestrictsFileUploadsToSchemaComponents;

    // ...
}

添加操作

添加一个返回操作的方法。方法名必须与操作名完全相同,或为操作名后接 Action

php
use App\Models\Post;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Concerns\RestrictsFileUploadsToSchemaComponents;
use Filament\Schemas\Contracts\HasSchemas;
use Livewire\Component;

class ManagePost extends Component implements HasActions, HasSchemas
{
    use InteractsWithActions;
    use InteractsWithSchemas;
    use RestrictsFileUploadsToSchemaComponents;

    public Post $post;

    public function deleteAction(): Action
    {
        return Action::make('delete')
            ->color('danger')
            ->requiresConfirmation()
            ->action(fn () => $this->post->delete());
    }
    
    // This method name also works, since the action name is `delete`:
    // public function delete(): Action
    
    // This method name does not work, since the action name is `delete`, not `deletePost`:
    // public function deletePost(): Action

    // ...
}

最后,需要在视图中渲染该操作。为此,可使用 {{ $this->deleteAction }},并将 deleteAction 替换为你的操作方法名:

blade
<div>
    {{ $this->deleteAction }}

    <x-filament-actions::modals />
</div>

你还需要 <x-filament-actions::modals />,它会注入渲染操作模态框所需的 HTML。无论该组件有多少个操作,只需在 Livewire 组件中包含一次即可。

INFO

filament/actions 还包含以下包:

  • filament/forms
  • filament/infolists
  • filament/notifications
  • filament/support

这些包允许你在 Livewire 组件中使用它们的组件。 例如,若你的操作使用了 Notifications,请记得在布局中包含 @livewire('notifications'),并在 CSS 文件中添加 @import '../../vendor/filament/notifications/resources/css/index.css'

若在操作中使用了其他 Filament 组件,请务必一并安装并集成对应的包。

传递操作参数

有时,你可能希望向操作传递参数。例如,若在同一视图中多次渲染同一操作,但每次针对不同模型,可将模型 ID 作为参数传入,之后再取回。为此,可在视图中调用该操作并以数组形式传入参数:

php
<div>
    @foreach ($posts as $post)
        <h2>{{ $post->title }}</h2>

        {{ ($this->deleteAction)(['post' => $post->id]) }}
    @endforeach

    <x-filament-actions::modals />
</div>

现在,你可以在操作方法中访问该帖子 ID:

php
use App\Models\Post;
use Filament\Actions\Action;

public function deleteAction(): Action
{
    return Action::make('delete')
        ->color('danger')
        ->requiresConfirmation()
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            $post?->delete();
        });
}

在 Livewire 视图中隐藏操作

若使用 hidden()visible() 控制操作是否渲染,应用 @if 检查 isVisible() 来包裹该操作:

blade
<div>
    @if ($this->deleteAction->isVisible())
        {{ $this->deleteAction }}
    @endif
    
    {{-- Or --}}
    
    @if (($this->deleteAction)(['post' => $post->id])->isVisible())
        {{ ($this->deleteAction)(['post' => $post->id]) }}
    @endif
</div>

hidden()visible() 方法也会控制操作是否 disabled(),因此在用户无权限时仍可用于保护操作不被执行。将此逻辑封装在操作自身的 hidden()visible() 中是良好实践,否则你需要在视图和 disabled() 中分别定义条件。

你还可以利用这一点,在操作隐藏时一并隐藏可能无需渲染的包裹元素:

blade
<div>
    @if ($this->deleteAction->isVisible())
        <div>
            {{ $this->deleteAction }}
        </div>
    @endif
</div>

在 Livewire 视图中分组操作

你可以通过 <x-filament-actions::group> Blade 组件将操作分组到下拉菜单中,并将 actions 数组作为属性传入:

blade
<div>
    <x-filament-actions::group :actions="[
        $this->editAction,
        $this->viewAction,
        $this->deleteAction,
    ]" />

    <x-filament-actions::modals />
</div>

你也可以传入任意属性来自定义触发按钮和下拉菜单的外观:

blade
<div>
    <x-filament-actions::group
        :actions="[
            $this->editAction,
            $this->viewAction,
            $this->deleteAction,
        ]"
        label="Actions"
        icon="heroicon-m-ellipsis-vertical"
        color="primary"
        size="md"
        tooltip="More actions"
        dropdown-placement="bottom-start"
    />

    <x-filament-actions::modals />
</div>

链式操作

你可以将多个操作串联起来:在当前操作完成后调用 replaceMountedAction() 方法,用另一个操作替换它:

php
use App\Models\Post;
use Filament\Actions\Action;

public function editAction(): Action
{
    return Action::make('edit')
        ->schema([
            // ...
        ])
        // ...
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            // ...

            $this->replaceMountedAction('publish', $arguments);
        });
}

public function publishAction(): Action
{
    return Action::make('publish')
        ->requiresConfirmation()
        // ...
        ->action(function (array $arguments) {
            $post = Post::find($arguments['post']);

            $post->publish();
        });
}

现在,提交第一个操作后,第二个操作会取而代之打开。原先传给第一个操作的参数会传给第二个操作,因此你可以用它们在请求之间持久化数据。

若取消第一个操作,第二个不会打开。若取消第二个操作,第一个已经执行,无法撤销。

以编程方式触发操作

有时你可能需要在用户未点击内置触发按钮的情况下触发操作,尤其是从 JavaScript 中。以下是一个可注册在 Livewire 组件上的示例操作:

php
use Filament\Actions\Action;

public function testAction(): Action
{
    return Action::make('test')
        ->requiresConfirmation()
        ->action(function (array $arguments) {
            dd('Test action called', $arguments);
        });
}

可在 HTML 中使用 wire:click 属性,通过调用 mountAction() 方法触发该操作,并可选择传入希望可用的任意参数:

blade
<button wire:click="mountAction('test', { id: 12345 })">
    Button
</button>

要从 JavaScript 触发该操作,可使用 $wire 工具,并传入相同参数:

js
$wire.mountAction('test', { id: 12345 })