我想运行一个名为
makeFinalAdjustments()
的 JavaScript 方法,但它需要在页面完成重新渲染此 Livewire 组件内的单击事件后的内容之后发生:
//CHILD LIVEWIRE COMPONENT
//Child.blade.php
<div>
<div wire:click="updateContent($id)">Click here</div>
<div>{{ $content }}</div>
....
</div>
//Child.php
public $content;
public $id;
public function updateContent()
{
$this->dispatch('updateContent');
}
//PARENT LIVEWIRE COMPONENT
//Parent.php
protected $listeners = [
'updateContent' => 'handleUpdateContent',
];
public function handleUpdateContent($child_id): void
{
$this->content[$child_id] = $this->getSomeContent($child_id);
}
//parent.blade.php
<div>
@foreach(child in list)
<livewire:child :content=content[child->id]>
@endforeach
...
</div>
我尝试根据文档添加事件监听器here....
document.addEventListener('livewire:init', function () {
Livewire.on('updateContent', () => {
Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
succeed(({ snapshot, effect }) => {
queueMicrotask(() => {
makeFinalAdjustments();
})
})
})
});
});
...但它不起作用,因为
makeFinalAdjustments()
在新内容完成渲染之前触发得太早。
问题还没有完全弄清楚,我们应该明白 makeFinalAdjustments() 函数中执行了什么。
无论如何,我尝试模拟这种情况,重建请求中不完整的部分。
家长课
class ParentTest extends Component
{
public array $content = [];
public array $children = [];
protected $listeners = [
'updateContent' => 'handleUpdateContent',
];
public function mount() {
$this->children = [
(object)['id' => 1],
(object)['id' => 2],
(object)['id' => 3],
];
$this->content = [
1 => Str::random(),
2 => Str::random(),
3 => Str::random()
];
}
public function handleUpdateContent($child_id): void
{
// $this->content[$child_id] = $this->getSomeContent($child_id);
$this->content[$child_id] = Str::random();
}
}
家长视图
<div>
@foreach($children as $child)
<livewire:child-test :content="$content[$child->id]" :id="$child->id" :key="$child->id">
<br>
<hr>
<br>
@endforeach
</div>
少儿班
namespace App\Livewire;
use Livewire\Attributes\Reactive;
use Livewire\Component;
class ChildTest extends Component
{
public $id;
#[Reactive]
public $content;
// --- since the event is now dispatched from the frontend this is no longer needed
//
// public function updateContent($id)
// {
// $this->dispatch('updateContent', child_id: $id);
// }
}
子视图
<div>
{{--<div wire:click="updateContent({{ $id }})">--}}
<div wire:click="$dispatch('updateContent', {child_id: {{ $id }} })"> {{-- <~~~ now the event is dispatched from the frontend --}}
[Click here]
</div>
<div x-init="$watch('$wire.content', () => $nextTick(() => makeFinalAdjustments({{ $id }})))">
<span id="content-{{ $id }}">
{{ $content }}
</span>
<span id="revContent-{{ $id }}">
</span>
</div>
</div>
<script>
function makeFinalAdjustments(id)
{
const content = document.getElementById(`content-${id}`).textContent;
const revContent = content.split("").reverse().join("");
document.getElementById(`revContent-${id}`).textContent = revContent;
}
</script>
在父类中,我使用一些随机字符串来模拟公共变量的初始内容content
在 handleUpdateContent() 事件处理程序中,我将 getSomeContent() 替换为新的随机字符串
在父视图中,我提供了 content 和 id 参数,我还添加了一个 unique key
子类的$content属性具有属性#[Reactive],因此父类中的更改会反映到相关子类
我从视图中调度了子组件事件,因此我保存了对后端的调用,并且不再需要子组件的 updateContent() 方法
在子视图中,我使用 Alpine 在 $wire.content 变量上添加了 $watch,因此当它发生更改时,会在 $nextTick 处调用 makeFinalAdjustments() 函数。
此测试中的 makeFinalAdjustments() 从 DOM 读取 content 并更新 revContent 元素:如您所见,使用 $nextTick makeFinalAdjustments() 在更新组件在Livewire端完成。 您将看到 Livewire 将所有 revContent 内容恢复为空,但随后与单击的按钮相关的 revContent 被填充