使用 属性 alpine js 和 livewire 调度浏览器事件
Dispatching browser event with property alpine js and livewire
我在使用 alpine 和 livewire 在浏览器上发送事件时尝试传递参数
第一次尝试的结果是我所期望的,id 与我通过的 属性 匹配:
但是在第二次尝试时,奇怪的事情发生了,id 与我通过的 属性 不匹配:
我传递参数的 blade 视图 :
<div>
<div class="card">
<div class="d-flex justify-content-between align-items-center card-header">
Todo List
<livewire:todos.todo-add />
</div>
<ul class="list-group list-group-flush">
@forelse ($todos as $todo)
<li class="list-group-item d-flex justify-content-between">
{{ $todo->title }}
<div x-data>
<button
class="btn btn-success"
@click.prevent="$dispatch('toast-confirmation', {
id: {{ $todo->id }},
action: 'complete',
message: 'Are you sure to complete this task ?'
})">Complete</button>
<button
class="btn btn-danger"
@click.prevent="$dispatch('alert-confirmation', {
id: {{ $todo->id }},
action: 'delete',
message: 'Are you sure to delete this task ?'
})">Delete</button>
</div>
</li>
@empty
No data.
@endforelse
</ul>
</div>
<div class="d-flex justify-content-end mt-3">
{{ $todos->links() }}
</div>
<x-alerts />
<x-toasters />
</div>
TodoIndex livewire class :
class TodoIndex extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
protected $listeners = [
'todoAdded' => '$refresh',
'complete',
'delete',
];
public function complete(Todo $todo)
{
$todo->update();
$this->dispatchBrowserEvent('toast', [
'type' => 'success',
'message' => 'Task has been completed'
]);
}
public function delete(Todo $todo)
{
$todo->delete();
$this->dispatchBrowserEvent('toast', [
'type' => 'success',
'message' => 'Task has been deleted'
]);
}
public function render()
{
return view('livewire.todos.todo-index', [
'todos' => Todo::latest()->paginate(5)
]);
}
}
警报(laravel-component):
<div>
@push('alerts')
<script>
// Alert Confirmation
window.addEventListener('alert-confirmation', event => {
Swal.fire({
title: 'Are you sure to delete this id : ' + event.detail.id + '?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
Livewire.emit(event.detail.action, event.detail.id)
}
})
})
// Alert Info
window.addEventListener('alert-info', event => {
Swal.fire({
icon: event.detail.icon,
title: 'Oops...',
text: 'Something went wrong!'
})
})
</script>
@endpush
</div>
app.layouts(laravel 分量):
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
<link rel="stylesheet" href="/css/style.css">
@livewireStyles
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.8.2/dist/alpine.min.js" defer></script>
</head>
<body>
<x-navbar />
<div class="container py-4">
{{ $slot }}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
{{-- SweetAlert2 --}}
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
{{-- Toastr --}}
<script src="/js/cute-alert/cute-alert.js"></script>
@stack('alerts')
@stack('toasters')
@livewireScripts
</body>
</html>
知道如何解决这个问题吗?
从 discord 得到答案,感谢 Josh Hansley 先生
实际上它在文档中也提到了 Dom Diffing Issue
在我的例子中,解决方案是像这样添加 wire:key="todo-{{ $todo->id }} :
<li class="list-group-item d-flex justify-content-between" wire:key="todo-{{ $todo->id }}">
{{ $todo->title }}
<div x-data>
<button
class="btn btn-success"
@click.prevent="$dispatch('toast-confirmation', {
id: {{ $todo->id }},
action: 'complete',
message: 'Are you sure to complete this task ?'
})">Complete</button>
<button
class="btn btn-danger"
@click.prevent="$dispatch('alert-confirmation', {
id: {{ $todo->id }},
action: 'delete',
message: 'Are you sure to delete this task ?'
})">Delete</button>
</div>
</li>
添加“todo-”前缀是最佳做法以避免发生一些奇怪的词态错误
我在使用 alpine 和 livewire 在浏览器上发送事件时尝试传递参数
第一次尝试的结果是我所期望的,id 与我通过的 属性 匹配:
但是在第二次尝试时,奇怪的事情发生了,id 与我通过的 属性 不匹配:
我传递参数的 blade 视图 :
<div>
<div class="card">
<div class="d-flex justify-content-between align-items-center card-header">
Todo List
<livewire:todos.todo-add />
</div>
<ul class="list-group list-group-flush">
@forelse ($todos as $todo)
<li class="list-group-item d-flex justify-content-between">
{{ $todo->title }}
<div x-data>
<button
class="btn btn-success"
@click.prevent="$dispatch('toast-confirmation', {
id: {{ $todo->id }},
action: 'complete',
message: 'Are you sure to complete this task ?'
})">Complete</button>
<button
class="btn btn-danger"
@click.prevent="$dispatch('alert-confirmation', {
id: {{ $todo->id }},
action: 'delete',
message: 'Are you sure to delete this task ?'
})">Delete</button>
</div>
</li>
@empty
No data.
@endforelse
</ul>
</div>
<div class="d-flex justify-content-end mt-3">
{{ $todos->links() }}
</div>
<x-alerts />
<x-toasters />
</div>
TodoIndex livewire class :
class TodoIndex extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
protected $listeners = [
'todoAdded' => '$refresh',
'complete',
'delete',
];
public function complete(Todo $todo)
{
$todo->update();
$this->dispatchBrowserEvent('toast', [
'type' => 'success',
'message' => 'Task has been completed'
]);
}
public function delete(Todo $todo)
{
$todo->delete();
$this->dispatchBrowserEvent('toast', [
'type' => 'success',
'message' => 'Task has been deleted'
]);
}
public function render()
{
return view('livewire.todos.todo-index', [
'todos' => Todo::latest()->paginate(5)
]);
}
}
警报(laravel-component):
<div>
@push('alerts')
<script>
// Alert Confirmation
window.addEventListener('alert-confirmation', event => {
Swal.fire({
title: 'Are you sure to delete this id : ' + event.detail.id + '?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
Livewire.emit(event.detail.action, event.detail.id)
}
})
})
// Alert Info
window.addEventListener('alert-info', event => {
Swal.fire({
icon: event.detail.icon,
title: 'Oops...',
text: 'Something went wrong!'
})
})
</script>
@endpush
</div>
app.layouts(laravel 分量):
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
<link rel="stylesheet" href="/css/style.css">
@livewireStyles
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.8.2/dist/alpine.min.js" defer></script>
</head>
<body>
<x-navbar />
<div class="container py-4">
{{ $slot }}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
{{-- SweetAlert2 --}}
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
{{-- Toastr --}}
<script src="/js/cute-alert/cute-alert.js"></script>
@stack('alerts')
@stack('toasters')
@livewireScripts
</body>
</html>
知道如何解决这个问题吗?
从 discord 得到答案,感谢 Josh Hansley 先生 实际上它在文档中也提到了 Dom Diffing Issue
在我的例子中,解决方案是像这样添加 wire:key="todo-{{ $todo->id }} :
<li class="list-group-item d-flex justify-content-between" wire:key="todo-{{ $todo->id }}">
{{ $todo->title }}
<div x-data>
<button
class="btn btn-success"
@click.prevent="$dispatch('toast-confirmation', {
id: {{ $todo->id }},
action: 'complete',
message: 'Are you sure to complete this task ?'
})">Complete</button>
<button
class="btn btn-danger"
@click.prevent="$dispatch('alert-confirmation', {
id: {{ $todo->id }},
action: 'delete',
message: 'Are you sure to delete this task ?'
})">Delete</button>
</div>
</li>
添加“todo-”前缀是最佳做法以避免发生一些奇怪的词态错误