使用 AlpineJS 和 @entangle 指令在 Livewire 中嵌套组件
Nested components in Livewire with AlpineJS and @entangle directive
我目前正在使用 Livewire 和 AlpineJS 开发一个项目。
我必须使用将 contenteditable 设置为“true”的 div 来访问和修改我的数据模型。
我想要的
我想使用 @entangle 在 Livewire 和 Alpine 之间共享状态。
我的代码
我的代码分为两部分。
第一部分依赖于 full-Page component,我只是在其中注册了一个 $fruits 数组。
第二个是一个包含“表单”的组件,允许我通过 @entangle 和一个 div 将 contenteditable 设置为 true.
来访问和修改数据。
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class ListFruit extends Component
{
protected $listeners = ['addFruit'];
public array $fruits = [];
public function mount()
{
$this->addFruit();
}
public function addFruit()
{
$this->fruits[] = $this->makeBlankFruit();
}
public function makeBlankFruit(): array
{
return [
'type' => '',
'color' => ''
];
}
public function render()
{
return view('livewire.list-fruit');
}
}
views/livewire/list-fruit.blade.php文件
<div class="w-full container mx-auto">
<h3 class="text-2xl font-sembibold">
Fruits
</h3>
<div id="fruits">
@foreach($fruits as $fruitIndex=> $fruit)
<livewire:fruit :fruitIndex="$fruitIndex" :fruit="fruit" :wire:key="$fruitIndex" >
@endforeach
</div>
</div>
水果成分
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Fruit extends Component
{
public array $fruit = [];
public string $fruitIndex;
public function render()
{
return view('livewire.fruit');
}
}
views/livewire/fruit.blade.php 文件
<div x-data="{type: @entangle('fruit.type'), color: @entangle('fruit.color')}"
x-init="console.log(type)"
>
<div>
<div x-on:blur="type = $event.target.innerHTML" contenteditable="true">{{ $fruit['type'] }}</div>
<div x-on:blur="color = $event.target.innerHTML" contenteditable="true">{{ $fruit['color'] }}</div>
</div>
<div>
$type @ Livewire: {{ $fruit['type'] }}
$color @ Livewire: {{ $fruit['color'] }}
</div>
<div>
type @ AlpineJS: <span x-text="type"></span>
color @ AlpineJS: <span x-text="color"></span>
</div>
</div>
如果我的主要组件中只有一个包含一些属性的数组,假设:
public array $fruit = [
'type' => '',
'color' => '',
];
我可以用我的水果访问它们。blade.php
我也尝试过这样的事情。
{type: @entangle('fruits.'. $fruitIndex.'.color'), color: @entangle('fruits.'. $fruitIndex.'.type')}
我得到了什么
在我的 AlpineJs 组件中,我读取了一个 [object Object] 代理,并且在修改我的 fruit.color 或 fruit.type 属性 时,livewire 部分没有更新。
我不知道为什么。
在我最后的尝试中,我尝试将我的水果分成多个子组件,以便我可以在一个数组上工作。
我正在寻找一个死胡同,所以在此先感谢您的帮助。
狸猫
我认为你应该简化你的例子。尽管您的 real-world 代码可能比您的(毫无疑问是人为的)水果示例更复杂,但在我看来没有必要在此处嵌套 Livewire 组件。保留一个 PHP/Livewire class 和一个 Blade 文件要简单得多。然后使用 Alpine 的 x-for
,而不是使用 Blade 和 @foreach
循环遍历您的数据。与当前趋势相反,我并不总是认为保持 file-sizes 较小是可取的,如果代价是层层嵌套(越来越难以调试)blade-templates(或 Livewire 组件)。
无论如何,抛开这一点,让我们回到你试图在这里建立的原则,这就是如何将 PHP/Livewire 数组与 Javascript/Alpine 变量纠缠在一起。
答案非常简单:您可以将任意复杂的 PHP data-structure(又名数组)与单个 JavaScript 变量纠缠在一起。正如您所期望的那样,如果您自己构建了框架,PHP 数组将简单地映射到 JSON object.
首先,设置你的复杂 back-end data-structure:
<?php
namespace App\Business\Tbd;
use Livewire\Component;
class StartLw extends Component
{
public array $fruits = [];
public function mount() {
$fruit_template = ['apple', 'banana', 'garlic'];
$fruit_colours = ['green', 'yellow', 'pink'];
$health_benefit = [
'keeps doctor away',
'the bend keeps you flexible',
'None. It\'s not really a fruit, though there is that vampire thing'
];
foreach ($fruit_template as $id => $fruit) {
$this->fruits[$fruit] = [
'colour' => $fruit_colours[$id],
'benefit' => $health_benefit[$id],
'bought_by' => array_slice(['Jim', 'John', 'Sue'], 0, $id+1),
];
}
}
public function render()
{
return view('my.livewire.template');
}
}
然后下面的 Blade 模板将告诉您所有您需要了解的 JavaScript/JSON object(最初创建于 PHP)的内容。
<div class="container-fluid">
<div class="row" x-data="{ fruits: @entangle('fruits') }">
<div class="col-11" id="main">
<p>Type of fruit: <span x-text="typeof fruits"></span></p>
<template x-for="(fruit_info, fruit) in fruits" :key="fruit">
<code>
Fruit type: <span x-text="fruit"></span><br />
Colour: <span x-text="fruit_info.colour"></span><br />
Health Superstitions: <span x-text="fruit_info.benefit"></span><br />
Bought by:
<template x-for="(pers, id) in fruit_info.bought_by" :key="id">
<span>
<span x-text="id"></span> => <span x-text="pers"></span>,
</span>
</template>
<br />
<br />
</code>
</template>
</div>
</div>
</div>
如您所见,如果您以足够的灵活性构建 Blade 模板,它们可以变得与底层 data-structure 无关,这(在模块化应用程序中)意味着它们可以被使用一遍又一遍。
我目前正在使用 Livewire 和 AlpineJS 开发一个项目。
我必须使用将 contenteditable 设置为“true”的 div 来访问和修改我的数据模型。
我想要的
我想使用 @entangle 在 Livewire 和 Alpine 之间共享状态。
我的代码
我的代码分为两部分。 第一部分依赖于 full-Page component,我只是在其中注册了一个 $fruits 数组。 第二个是一个包含“表单”的组件,允许我通过 @entangle 和一个 div 将 contenteditable 设置为 true.
来访问和修改数据。<?php
namespace App\Http\Livewire;
use Livewire\Component;
class ListFruit extends Component
{
protected $listeners = ['addFruit'];
public array $fruits = [];
public function mount()
{
$this->addFruit();
}
public function addFruit()
{
$this->fruits[] = $this->makeBlankFruit();
}
public function makeBlankFruit(): array
{
return [
'type' => '',
'color' => ''
];
}
public function render()
{
return view('livewire.list-fruit');
}
}
views/livewire/list-fruit.blade.php文件
<div class="w-full container mx-auto">
<h3 class="text-2xl font-sembibold">
Fruits
</h3>
<div id="fruits">
@foreach($fruits as $fruitIndex=> $fruit)
<livewire:fruit :fruitIndex="$fruitIndex" :fruit="fruit" :wire:key="$fruitIndex" >
@endforeach
</div>
</div>
水果成分
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Fruit extends Component
{
public array $fruit = [];
public string $fruitIndex;
public function render()
{
return view('livewire.fruit');
}
}
views/livewire/fruit.blade.php 文件
<div x-data="{type: @entangle('fruit.type'), color: @entangle('fruit.color')}"
x-init="console.log(type)"
>
<div>
<div x-on:blur="type = $event.target.innerHTML" contenteditable="true">{{ $fruit['type'] }}</div>
<div x-on:blur="color = $event.target.innerHTML" contenteditable="true">{{ $fruit['color'] }}</div>
</div>
<div>
$type @ Livewire: {{ $fruit['type'] }}
$color @ Livewire: {{ $fruit['color'] }}
</div>
<div>
type @ AlpineJS: <span x-text="type"></span>
color @ AlpineJS: <span x-text="color"></span>
</div>
</div>
如果我的主要组件中只有一个包含一些属性的数组,假设:
public array $fruit = [
'type' => '',
'color' => '',
];
我可以用我的水果访问它们。blade.php
我也尝试过这样的事情。
{type: @entangle('fruits.'. $fruitIndex.'.color'), color: @entangle('fruits.'. $fruitIndex.'.type')}
我得到了什么
在我的 AlpineJs 组件中,我读取了一个 [object Object] 代理,并且在修改我的 fruit.color 或 fruit.type 属性 时,livewire 部分没有更新。
我不知道为什么。 在我最后的尝试中,我尝试将我的水果分成多个子组件,以便我可以在一个数组上工作。
我正在寻找一个死胡同,所以在此先感谢您的帮助。 狸猫
我认为你应该简化你的例子。尽管您的 real-world 代码可能比您的(毫无疑问是人为的)水果示例更复杂,但在我看来没有必要在此处嵌套 Livewire 组件。保留一个 PHP/Livewire class 和一个 Blade 文件要简单得多。然后使用 Alpine 的 x-for
,而不是使用 Blade 和 @foreach
循环遍历您的数据。与当前趋势相反,我并不总是认为保持 file-sizes 较小是可取的,如果代价是层层嵌套(越来越难以调试)blade-templates(或 Livewire 组件)。
无论如何,抛开这一点,让我们回到你试图在这里建立的原则,这就是如何将 PHP/Livewire 数组与 Javascript/Alpine 变量纠缠在一起。
答案非常简单:您可以将任意复杂的 PHP data-structure(又名数组)与单个 JavaScript 变量纠缠在一起。正如您所期望的那样,如果您自己构建了框架,PHP 数组将简单地映射到 JSON object.
首先,设置你的复杂 back-end data-structure:
<?php
namespace App\Business\Tbd;
use Livewire\Component;
class StartLw extends Component
{
public array $fruits = [];
public function mount() {
$fruit_template = ['apple', 'banana', 'garlic'];
$fruit_colours = ['green', 'yellow', 'pink'];
$health_benefit = [
'keeps doctor away',
'the bend keeps you flexible',
'None. It\'s not really a fruit, though there is that vampire thing'
];
foreach ($fruit_template as $id => $fruit) {
$this->fruits[$fruit] = [
'colour' => $fruit_colours[$id],
'benefit' => $health_benefit[$id],
'bought_by' => array_slice(['Jim', 'John', 'Sue'], 0, $id+1),
];
}
}
public function render()
{
return view('my.livewire.template');
}
}
然后下面的 Blade 模板将告诉您所有您需要了解的 JavaScript/JSON object(最初创建于 PHP)的内容。
<div class="container-fluid">
<div class="row" x-data="{ fruits: @entangle('fruits') }">
<div class="col-11" id="main">
<p>Type of fruit: <span x-text="typeof fruits"></span></p>
<template x-for="(fruit_info, fruit) in fruits" :key="fruit">
<code>
Fruit type: <span x-text="fruit"></span><br />
Colour: <span x-text="fruit_info.colour"></span><br />
Health Superstitions: <span x-text="fruit_info.benefit"></span><br />
Bought by:
<template x-for="(pers, id) in fruit_info.bought_by" :key="id">
<span>
<span x-text="id"></span> => <span x-text="pers"></span>,
</span>
</template>
<br />
<br />
</code>
</template>
</div>
</div>
</div>
如您所见,如果您以足够的灵活性构建 Blade 模板,它们可以变得与底层 data-structure 无关,这(在模块化应用程序中)意味着它们可以被使用一遍又一遍。