capevace / livewire-optimistic-ui
一个用于在 Laravel Livewire 中更好地支持乐观 UI 的实用程序包。
Requires
- php: ^8.2
- illuminate/contracts: ^10.0||^11.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^9.0.0||^8.22.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
README
Demo.mp4
安装
您可以通过 composer 安装此包
composer require capevace/livewire-optimistic-ui
示例
# In your Livewire component's .blade.php file <x-optimistic::injector class="max-w-lg mx-auto mt-10"> <x-demo.saving-indicator wire:loading.delay /> <form class="w-full flex items-center gap-5 mb-10" x-data="{ text: '' }" @submit.prevent=" $optimistic.addTask(text); text = ''; " > <input autofocus name="text" x-model="text" placeholder="Type your task here..." class="flex-1 px-5 py-3 border shadow rounded-lg" /> <button class="px-5 py-3 border shadow rounded-lg bg-green-400">Add +</button> </form> <x-demo.list> @foreach($todos as $task) <x-demo.task wire:key="{{ $task['id'] }}" x-optimistic x-optimistic.removed.remove > <x-demo.button @click="$optimistic.deleteTask('{{ $task['id'] }}')"/> <form x-data="{ text: $item?.text ?? @js($task['text']), }" class="flex-1" > <x-demo.input name="text_{{ $task['id'] }}" x-model="text" x-optimistic.edited.class="italic" @input.debounce="$optimistic.editTask('{{ $task['id'] }}', text)" /> </form> </x-demo.task> @endforeach <x-optimistic::added> <x-demo.task x-bind:data-id="$item.id" x-bind:wire:key="$item.id" x-optimistic.removed.remove > <x-demo.button @click="$optimistic.deleteTask($item.id)"/> <div class="flex-1"> <x-demo.input x-bind:name="'text_' + $item.id" x-bind:value="$item.text" class="italic" /> </div> </x-demo.task> </x-optimistic::added> </x-demo.list> </x-optimistic::injector>
use Capevace\OptimisticUI\WithOptimisticUI; use Capevace\OptimisticUI\Optimistic; /** * @property-read Collection $todos */ class OptimisticPage extends Component { use WithOptimisticUI; #[Optimistic(crud: 'create', model: Task::class, injectOptimisticId: true)] public function addTask(string $id, string $text): void { if (!uuid_is_valid($id) || Task::find($id)) { return; } $task = new Task([ 'text' => $text, ]); $task->id = $id; $task->save(); } #[Optimistic(crud: 'delete', model: Task::class)] public function deleteTask(string $id): void { Task::find($id)?->delete(); } #[Optimistic(crud: 'update', model: Task::class)] public function editTask(string $id, string $text): void { Task::find($id)?->update([ 'text' => $text, ]); } #[Computed] public function todos(): Collection { return Task::all(); } public function render(): \Illuminate\View\View { return view("messages", [ 'todos' => $this->todos, ]); } }
用法
将乐观 UI 添加到您的 Livewire 组件中
您需要使用 x-optimistic::injector
组件包裹您的 UI。此组件将为您处理乐观 UI。
<x-optimistic::injector class="max-w-lg mx-auto mt-10"> <!-- Your UI here --> </x-optimistic::injector>
然后,您可以通过使用 $optimistic
对象来乐观地调用您的函数。
<form @submit.prevent=" $optimistic.addTask(text); text = ''; " > <input x-model="text" /> </form> <!-- OR --> @foreach($todos as $task) <form x-data="{ text: $item?.text ?? @js($task['text']) }" @submit.prevent="$optimistic.editTask('{{ $task['id'] }}', text)" > <input x-model="text" /> </form> @endforeach
显示添加的项目
您可以使用 x-optimistic::added
指令来显示通过乐观方式添加的项目。组件将循环所有添加的项目,并将每个项目存储在 $item
变量中。
<x-optimistic::added> <x-demo.task x-bind:data-id="$item.id" x-bind:wire:key="$item.id" > <div x-text="$item.text"></div> </x-demo.task> </x-optimistic::added>
乐观指令
您可以将 x-optimistic
指令添加到注入给定项目的乐观状态。ID 将从 wire:key
属性推断出来,或者可以通过 x-optimistic="<id>"
传递。
<x-demo.task x-optimistic x-optimistic.edited.class="italic" x-optimistic.removed.remove > <!-- Your task here --> </x-demo.task>
乐观函数
要向您的 Livewire 组件添加乐观函数,您可以使用 #[Optimistic]
属性。
use Capevace\OptimisticUI\Optimistic; #[Optimistic( fn: "update(params[0], { message: params[1] })" )] public function changeMessage(string $id, string $message): void { Message::find($id)->update([ 'message' => $message, ]); }
fn
参数中的 JavaScript 将在函数被调用时在客户端执行。params
数组包含传递给函数的参数。
本地生成 ID
在创建新项目时,将为项目生成一个新的 UUID。此 ID 识别正在传输中的项目。如果您使用此 ID 实际创建项目,则可以支持与正在传输的项目交互,因为它们将被排队。
要使用此功能,请将 injectOptimisticId
参数设置为 true
。
本地,您仍然会调用 $optimized.addTask(text)
,但 ID 将在服务器端注入。
#[Optimistic( fn: "create({ text: params[0] })" injectOptimisticId: true )] public function addTask(string $id, string $text): void { if (!uuid_is_valid($id) || Task::find($id)) { return; } $task = new Task([ 'text' => $text, ]); $task->id = $id; $task->save(); }
现成的 CRUD 函数
最常用的函数已通过 crud
参数实现。
将此设置为 create
、update
或 delete
将使用反射检查您的 PHP 函数参数,并自动为您生成 JavaScript 函数。
您还需要提供 model
参数,它将用于仅允许更新 fillable
属性。
#[Optimistic(crud: 'create', model: Task::class)] public function addTask(string $id, string $text): void { if (!uuid_is_valid($id) || Task::find($id)) { return; } $task = new Task([ 'text' => $text, ]); $task->id = $id; $task->save(); } #[Optimistic(crud: 'delete', model: Task::class)] public function deleteTask(string $id): void { Task::find($id)?->delete(); } #[Optimistic(crud: 'update', model: Task::class)] public function editTask(string $id, string $text): void { Task::find($id)?->update([ 'text' => $text, ]); }
测试
composer test
变更日志
有关最近更改的更多信息,请参阅 CHANGELOG。
贡献
有关详细信息,请参阅 CONTRIBUTING。
安全漏洞
有关如何报告安全漏洞的详细信息,请参阅 我们的安全策略。
致谢
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。