Livewire 如何工作
- 组件 * Counter 组件
- 渲染组件 * 挂载(Mount) * 实例化类 * 脱水状态 * 嵌入 HTML * 返回 HTML
- 在 JS 中初始化组件 * 查找 wire:id 元素 * 提取 id 与快照 * 创建对象
- 发送更新 * 注册事件监听器 * 发送带更新与快照的 fetch 请求
- 接收更新 * 将快照转为组件(水合) * 应用更新 * 渲染组件 * 返回 HTML 与新快照
- 处理更新 * 用新快照替换 * 用新 HTML 替换 * Morphing
组件
php
<?php
use Livewire\Component;
class Counter extends Component
{
public $count = 1;
public function increment()
{
$this->count++;
}
public function render()
{
return view('livewire.counter');
}
}blade
<div>
<button wire:click="increment">Increment</button>
<span>{{ $count }}</span>
</div>渲染组件
blade
<livewire:counter />php
<?php echo Livewire::mount('counter'); ?>php
public function mount($name)
{
$class = Livewire::getComponentClassByName();
$component = new $class;
$id = str()->random(20);
$component->setId($id);
$data = $component->getData();
$view = $component->render();
$html = $view->render($data);
$snapshot = [
'data' => $data,
'memo' => [
'id' => $component->getId(),
'name' => $component->getName(),
]
];
return Livewire::embedSnapshotInsideHtml($html, $snapshot);
}blade
<div wire:id="123456789" wire:snapshot="{ data: { count: 0 }, memo: { 'id': '123456789', 'name': 'counter' }">
<button wire:click="increment">Increment</button>
<span>1</span>
</div>JavaScript 初始化
js
let el = document.querySelector('wire\\:id')
let id = el.getAttribute('wire:id')
let jsonSnapshot = el.getAttribute('wire:snapshot')
let snapshot = JSON.parse(jsonSnapshot)
let component = { id, snapshot }
walk(el, el => {
el.hasAttribute('wire:click') {
let action = el.getAttribute('wire:click')
el.addEventListener('click', e => {
updateComponent(el, component, action)
})
}
})
function updateComponent(el, component, action) {
let response fetch('/livewire/update', {
body: JSON.stringify({
"snapshot": snapshot,
"calls": [
["method": action, "params": []],
]
})
})
// To be continued...
}接收更新
php
Route::post('/livewire/update', function () {
$snapshot = request('snapshot');
$calls = request('calls');
$component = Livewire::fromSnapshot($snapshot);
foreach ($calls as $call) {
$component->{$call['method']}(...$call['params']);
}
[$html, $snapshot] = Livewire::snapshot($component);
return [
'snapshot' => $snapshot,
'html' => $html,
];
});处理更新
js
function updateComponent(el, component, action) {
fetch('/livewire/update', {
body: JSON.stringify({
"snapshot": snapshot,
"calls": [
["method": action, "params": []],
]
})
}).then(i => i.json()).then(response => {
let { html, snapshot } = response
component.snapshot = snapshot
el.outerHTML = html
})
}