【发布时间】:2022-01-11 16:21:35
【问题描述】:
我有一个 alpine js 和 livewire 组件,用于显示列表中的添加和删除项目。每个项目都显示为一个令牌。
这是令牌的 HTML 代码:
<div
class="inline-block px-2 py-4"
x-data="{show : false}"
x-show="show"
x-init="setTimeout(() => {show=true}, 450)"
x-transition.duration.450>
<span class="px-4 py-3 space-x-1 rounded-full shadow bg-indigo-300 text-white font-light">
<span>{{ $item->name }}</span>
<span
class="font-bold text-xl cursor-pointer"
@click="show = false;
setTimeout(() => {$wire.updateSelection({{ $item->id }})}, 400);">
×
</span>
</span>
<input type="text" name="clients[]" type="number" value="{{ $item->id }}" hidden />
</div>
我需要令牌在从 DOM 中移除之前顺利消失。为了实现这一点,我尝试应用以下代码。
@click="show = false; setTimeout(() => {$wire.updateSelection({{ $item->id }})}, 400);">
问题在于,一旦标记被隐藏,然后通过 livewire 方法从数组中删除,循环中的下一个标记仍然隐藏,因为它的 show 属性现在设置为 false。这是为什么呢?
这是一个演示:https://gfycat.com/brightbronzeherring
我尝试通过添加一个额外的 setTimeout 来修复它,但它运行不顺畅。使用此解决方案时,如果您决定删除最后显示的令牌,则会添加不需要的动画:
@click="show = false; setTimeout(() => {$wire.updateSelection({{ $item->id }})}, 400); setTimeout(() => {show=true}, 300);">
这是livewire组件的php代码:
<?php
namespace App\Http\Livewire\Components;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Component;
class ManyToManyDropdown extends Component
{
public $selected;
public $noUsers;
public $link;
// PTR add comments
public function mount($link)
{
if (!empty($link)) { // when the form is used in the 'create' view we pass an empty string PTR
$this->link = $link;
$this->selected = $link->users; // load the users which have already been selected
$this->noUsers = $this->selected->count() > 0 ? false : true; // determine if the 'no users message should be displayed'
} else {
$this->selected = new Collection();
$this->noUsers = true;
}
}
// PTR add comments
public function updateSelection($id)
{
// validate the data
$valid = User::all()->pluck('id')->contains($id);
if (!$valid) { // if data validation fails - abort
return abort(404);
}
// persis the data
$found = $this->selected->pluck('id')->contains($id);
$user = User::find($id);
if ($found) { // in case the item is already in the collection we remove it
$this->selected = $this->selected->filter(function ($item) use ($id) {
return $item->id != $id;
});
} else { // in case the item is not in the collection then it is added
$this->selected->push($user);
}
$this->noUsers = $this->selected->count() == 0 ? true :false ; // check if a 'no items message should be shown'
}
// PTR add comments
public function render()
{
return view('livewire.components.many-to-many-dropdown', [
'users' => User::clients()->get()
]);
}
}
这是 HTML:
<div class="space-y-4">
<!-- Clients -->
<div>
<x-label class="font-bold" for="Client" :value="__('Client:')" />
<div>
@foreach ($selected as $item)
<div
class="inline-block px-2 py-4"
x-data="{show : false}"
x-show="show"
x-init="setTimeout(() => {show=true}, 450)"
x-transition.duration.450>
<span class="px-4 py-3 space-x-1 rounded-full shadow bg-indigo-300 text-white font-light">
<span>{{ $item->name }}</span>
<span
class="font-bold text-xl cursor-pointer"
@click="show = false;
setTimeout(() => {$wire.updateSelection({{ $item->id }})}, 400);
setTimeout(() => {show=true}, 300);">
×
</span>
</span>
<input type="text" name="clients[]" type="number" value="{{ $item->id }}" hidden />
</div>
@endforeach
</div>
{{-- message in case there are not users selcted for this link --}}
<div x-data="{show: @entangle('noUsers')}" x-show="show" x-transition.duration.450ms
class="mt-1 px-2 py-2 cursor-not-allowed text-sm rounded-md shadow-sm border border-gray-400 itlaic font-hairline">
There are no customers selected...
</div>
</div>
<!-- Dropdown -->
<div>
<x-label class="font-bold" :value="__('Assign to:')" />
<div x-data="{show:false}" class="mt-1 relative">
<button
@click="show = !show;" type="button"
class="relative w-full bg-white border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-300 focus:border-indigo-500 sm:text-sm"
aria-haspopup="listbox"
aria-expanded="true"
aria-labelledby="listbox-label">
<span x-ref="button" class="block truncate">
Select users...
</span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<!-- Heroicon name: solid/selector -->
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</span>
</button>
<ul x-show="show" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100" @click.away='show = false'
class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
tabindex="-1" role="listbox" aria-labelledby="listbox-label" aria-activedescendant="listbox-option-3">
@foreach ($users as $user)
{{-- in case the array contains tha user I remove it, otherwise I add it --}}
<li x-data="{showCheck : false}" @click="showCheck = !showCheck"
wire:click="updateSelection('{{ $user->id }}')"
class="text-gray-900 cursor-default select-none relative py-2 pl-8 pr-4 hover:bg-blue-300 hover:text-white"
role="option">
<span class="font-normal block truncate">
{{ $user->name }}
</span>
<span x-show="showCheck" x-transition.duration.400ms
class="text-indigo-600 absolute inset-y-0 left-0 flex items-center pl-1.5">
<!-- Heroicon name: solid/check -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
</span>
</li>
@endforeach
</ul>
</div>
</div>
</div>
【问题讨论】:
标签: laravel laravel-livewire alpine.js