Skip to content

JavaScript

在 Livewire 组件中使用 JavaScript

Livewire 和 Alpine 提供了大量实用工具,可以直接在 HTML 中构建动态组件,但是,有时候在组件中执行纯 JavaScript 会很有帮助。

类组件需要 @script 指令

本页面的示例使用裸 <script> 标签,这适用于单文件多文件组件。如果您使用的是类组件(Blade 视图与 PHP 类在不同文件中),您必须用 @script 指令包裹您的 script 标签:

blade
@script
<script>
    // 您的 JavaScript 代码...
</script>
@endscript

这告诉 Livewire 为类组件正确处理执行时机。

执行脚本

您可以直接在组件模板内添加 <script> 标签,以便在组件加载时执行 JavaScript。

因为这些脚本由 Livewire 处理,它们在完美的时机执行——在页面加载后,但在 Livewire 组件渲染之前。这意味着您不再需要用 document.addEventListener('...') 包裹脚本来正确加载它们。

这也意味着延迟加载或条件加载的 Livewire 组件在页面初始化后仍然能够执行 JavaScript。

blade
<div>
    ...
</div>

<script>
    // 每次将此组件加载到页面时,此 JavaScript 都会执行...
</script>

这是一个更完整的示例,您可以在其中注册在 Livewire 组件中使用的 JavaScript 操作。

blade
<div>
    <button wire:click="$js.increment">+</button>
</div>

<script>
    this.$js.increment = () => {
        console.log('increment')
    }
</script>

要了解更多关于 JavaScript 操作的信息,请访问操作文档

从脚本中使用 $wire

当您在组件内添加 <script> 标签时,您会自动获得对 Livewire 组件的 $wire 对象的访问权限。

以下是使用简单的 setInterval 每 2 秒刷新组件的示例(您可以轻松地使用 wire:poll 来实现这一点,但这是演示要点的简单方式):

blade
<script>
    setInterval(() => {
        $wire.$refresh()
    }, 2000)
</script>

$wire 对象

$wire 对象是您与 Livewire 组件交互的 JavaScript 接口。它提供对组件属性、方法和与服务器交互的实用程序的访问。

在组件脚本内,您可以直接使用 $wire。以下是您将使用的最基本方法:

js
// 访问和修改属性
$wire.count
$wire.count = 5
$wire.$set('count', 5)

// 调用组件方法
$wire.save()
$wire.delete(postId)

// 刷新组件
$wire.$refresh()

// 分发事件
$wire.$dispatch('post-created', { postId: 2 })

// 监听事件
$wire.$on('post-created', (event) => {
    console.log(event.postId)
})

// 访问根元素
$wire.$el.querySelector('.modal')

完整的 $wire 参考

有关所有 $wire 方法和属性的完整列表,请参阅本页底部的 $wire 参考

加载资源

组件 <script> 标签对于在每次 Livewire 组件加载时执行一些 JavaScript 很有用,但是,有时您可能希望随组件一起在页面上加载整个脚本和样式资源。

以下是使用 @assets 加载名为 Pikaday 的日期选择器库并在组件内初始化它的示例:

blade
<div>
    <input type="text" data-picker>
</div>

@assets
<script src="https://cdn.jsdelivr.net/npm/pikaday/pikaday.js" defer></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css">
@endassets

<script>
    new Pikaday({ field: $wire.$el.querySelector('[data-picker]') });
</script>

当此组件加载时,Livewire 将确保在评估脚本之前加载页面上的任何 @assets。此外,它将确保提供的 @assets 在每个页面上只加载一次,无论此组件有多少个实例,这与组件脚本不同,组件脚本会为页面上的每个组件实例进行评估。

拦截器

在三个级别拦截 Livewire 请求:action(最精细)、message(每个组件)和 request(HTTP 级别)。

js
// Action 拦截器 - 为每个 action 调用触发
$wire.intercept(callback)                     // 此组件上的所有 action
$wire.intercept('save', callback)             // 仅 'save' action
Livewire.interceptAction(callback)            // 全局(所有组件)

// Message 拦截器 - 为每个组件消息触发
$wire.interceptMessage(callback)              // 来自此组件的消息
$wire.interceptMessage('save', callback)      // 仅当消息包含 'save'
Livewire.interceptMessage(callback)           // 全局(所有组件)

// Request 拦截器 - 为每个 HTTP 请求触发
$wire.interceptRequest(callback)              // 涉及此组件的请求
$wire.interceptRequest('save', callback)      // 仅当请求包含 'save'
Livewire.interceptRequest(callback)           // 全局(所有请求)

所有拦截器都返回一个取消订阅函数:

js
let unsubscribe = $wire.intercept(callback)
unsubscribe() // 移除拦截器

Action 拦截器

Action 拦截器是最精细的。它们为组件上的每个方法调用触发。

js
$wire.intercept(({ action, onSend, onCancel, onSuccess, onError, onFailure, onFinish }) => {
    // action.name        - 方法名称 ('save', '$refresh' 等)
    // action.params      - 方法参数
    // action.component   - 组件实例
    // action.cancel()    - 取消此 action

    onSend(({ call }) => {
        // call: { method, params, metadata }
    })

    onCancel(() => {})

    onSuccess((result) => {
        // result: PHP 方法的返回值
    })

    onError(({ response, body, preventDefault }) => {
        preventDefault() // 阻止错误模态框
    })

    onFailure(({ error }) => {
        // error: 网络错误
    })

    onFinish(() => {
        // 始终运行(成功、错误、失败或取消)
    })
})

Message 拦截器

Message 拦截器为每个组件更新触发。一个消息包含一个或多个 action。

js
$wire.interceptMessage(({ message, cancel, onSend, onCancel, onSuccess, onError, onFailure, onStream, onFinish }) => {
    // message.component  - 组件实例
    // message.actions    - 此消息中的 action 集合
    // cancel()           - 取消此消息

    onSend(({ payload }) => {
        // payload: { snapshot, updates, calls }
    })

    onCancel(() => {})

    onSuccess(({ payload, onSync, onEffect, onMorph, onRender }) => {
        // payload: { snapshot, effects }

        onSync(() => {})    // 状态同步后
        onEffect(() => {})  // 效果处理后
        onMorph(async () => {})   // DOM morph 后(必须是 async)
        onRender(() => {})  // 渲染完成后
    })

    onError(({ response, body, preventDefault }) => {
        preventDefault() // 阻止错误模态框
    })

    onFailure(({ error }) => {})

    onStream(({ json }) => {
        // json: 解析的流式数据块
    })

    onFinish(() => {})
})

Request 拦截器

Request 拦截器为每个 HTTP 请求触发。一个请求可能包含来自多个组件的消息。

js
$wire.interceptRequest(({ request, onSend, onCancel, onSuccess, onError, onFailure, onResponse, onParsed, onStream, onRedirect, onDump, onFinish }) => {
    // request.messages   - 此请求中的消息集合
    // request.cancel()   - 取消此请求

    onSend(({ responsePromise }) => {})

    onCancel(() => {})

    onResponse(({ response }) => {
        // response: Fetch Response(读取 body 之前)
    })

    onParsed(({ response, body }) => {
        // body: 响应体作为字符串
    })

    onSuccess(({ response, body, json }) => {})

    onError(({ response, body, preventDefault }) => {
        preventDefault() // 阻止错误模态框
    })

    onFailure(({ error }) => {})

    onStream(({ response }) => {})

    onRedirect(({ url, preventDefault }) => {
        preventDefault() // 阻止重定向
    })

    onDump(({ html, preventDefault }) => {
        preventDefault() // 阻止 dump 模态框
    })

    onFinish(() => {})
})

示例

组件的加载状态:

blade
<script>
    $wire.intercept(({ onSend, onFinish }) => {
        onSend(() => $wire.$el.classList.add('opacity-50'))
        onFinish(() => $wire.$el.classList.remove('opacity-50'))
    })
</script>

删除前确认:

blade
<script>
    $wire.intercept('delete', ({ action }) => {
        if (!confirm('确定要删除吗?')) {
            action.cancel()
        }
    })
</script>

全局会话过期处理:

js
Livewire.interceptRequest(({ onError }) => {
    onError(({ response, preventDefault }) => {
        if (response.status === 419) {
            preventDefault()
            if (confirm('会话已过期。刷新页面?')) {
                window.location.reload()
            }
        }
    })
})

Action 特定的成功通知:

blade
<script>
    $wire.intercept('save', ({ onSuccess, onError }) => {
        onSuccess(() => showToast('已保存!'))
        onError(() => showToast('保存失败', 'error'))
    })
</script>

全局 Livewire 事件

Livewire 为您分发两个有用的浏览器事件,以便从外部脚本注册任何自定义扩展点:

html
<script>
    document.addEventListener('livewire:init', () => {
        // 在 Livewire 加载后但在页面初始化之前运行...
    })

    document.addEventListener('livewire:initialized', () => {
        // 在 Livewire 完成页面初始化后立即运行...
    })
</script>

INFO

通常在 livewire:init 内注册任何自定义指令生命周期钩子会很有益,这样它们在 Livewire 开始在页面上初始化之前就可用了。

Livewire 全局对象

Livewire 的全局对象是从外部脚本与 Livewire 交互的最佳起点。

您可以从客户端代码的任何位置在 window 上访问全局 Livewire JavaScript 对象。

livewire:init 事件监听器内使用 window.Livewire 通常很有帮助。

访问组件

您可以使用以下方法访问当前页面上加载的特定 Livewire 组件:

js
// 获取页面上第一个组件的 $wire 对象...
let component = Livewire.first()

// 通过 ID 获取给定组件的 `$wire` 对象...
let component = Livewire.find(id)

// 通过名称获取组件 `$wire` 对象的数组...
let components = Livewire.getByName(name)

// 获取页面上每个组件的 $wire 对象...
let components = Livewire.all()

INFO

这些方法中的每一个都返回一个表示组件在 Livewire 中状态的 $wire 对象。

您可以在 $wire 文档 中了解更多关于这些对象的信息。

与事件交互

除了从 PHP 中的单个组件分发和监听事件外,全局 Livewire 对象允许您从应用程序的任何位置与 Livewire 的事件系统 交互:

js
// 向任何正在监听的 Livewire 组件分发事件...
Livewire.dispatch('post-created', { postId: 2 })

// 通过名称向给定的 Livewire 组件分发事件...
Livewire.dispatchTo('dashboard', 'post-created', { postId: 2 })

// 监听从 Livewire 组件分发的事件...
Livewire.on('post-created', ({ postId }) => {
    // ...
})

在某些场景中,您可能需要注销全局 Livewire 事件。例如,当使用 Alpine 组件和 wire:navigate 时,由于在页面之间导航时会调用 init,可能会注册多个监听器。要解决这个问题,请使用 Alpine 自动调用的 destroy 函数。在此函数内循环遍历所有监听器以注销它们,防止任何不需要的累积。

js
Alpine.data('MyComponent', () => ({
    listeners: [],
    init() {
        this.listeners.push(
            Livewire.on('post-created', (options) => {
                // 做一些事情...
            })
        );
    },
    destroy() {
        this.listeners.forEach((listener) => {
            listener();
        });
    }
}));

使用生命周期钩子

Livewire 允许您使用 Livewire.hook() 挂钩到其全局生命周期的各个部分:

js
// 注册一个回调以在给定的内部 Livewire 钩子上执行...
Livewire.hook('component.init', ({ component, cleanup }) => {
    // ...
})

有关 Livewire 的 JavaScript 钩子的更多信息可以在下面找到

注册自定义指令

Livewire 允许您使用 Livewire.directive() 注册自定义指令。

以下是自定义 wire:confirm 指令的示例,它使用 JavaScript 的 confirm() 对话框在发送到服务器之前确认或取消操作:

html
<button wire:confirm="确定吗?" wire:click="delete">删除文章</button>

以下是使用 Livewire.directive() 实现 wire:confirm 的方法:

js
Livewire.directive('confirm', ({ el, directive, component, cleanup }) => {
    let content =  directive.expression

    // "directive" 对象让您访问解析后的指令。
    // 例如,对于 wire:click.prevent="deletePost(1)" 的值如下:
    //
    // directive.raw = wire:click.prevent
    // directive.value = "click"
    // directive.modifiers = ['prevent']
    // directive.expression = "deletePost(1)"

    let onClick = e => {
        if (! confirm(content)) {
            e.preventDefault()
            e.stopImmediatePropagation()
        }
    }

    el.addEventListener('click', onClick, { capture: true })

    // 在 `cleanup()` 内注册任何清理代码,以防
    // 在页面仍处于活动状态时从 DOM 中移除 Livewire 组件。
    cleanup(() => {
        el.removeEventListener('click', onClick)
    })
})

JavaScript 钩子

对于高级用户,Livewire 暴露了其内部客户端"钩子"系统。您可以使用以下钩子来扩展 Livewire 的功能或获取有关 Livewire 应用程序的更多信息。

组件初始化

每当 Livewire 发现新组件时——无论是在初始页面加载时还是之后——都会触发 component.init 事件。您可以挂钩到 component.init 以拦截或初始化与新组件相关的任何内容:

js
Livewire.hook('component.init', ({ component, cleanup }) => {
    //
})

有关更多信息,请参阅组件对象的文档

DOM 元素初始化

除了在初始化新组件时触发事件外,Livewire 还为给定 Livewire 组件内的每个 DOM 元素触发事件。

这可用于在您的应用程序中提供自定义 Livewire HTML 属性:

js
Livewire.hook('element.init', ({ component, el }) => {
    //
})

DOM Morph 钩子

在 DOM morphing 阶段——发生在 Livewire 完成网络往返之后——Livewire 会为每个被修改的元素触发一系列事件。

js
Livewire.hook('morph.updating',  ({ el, component, toEl, skip, childrenOnly }) => {
    //
})

Livewire.hook('morph.updated', ({ el, component }) => {
    //
})

Livewire.hook('morph.removing', ({ el, component, skip }) => {
    //
})

Livewire.hook('morph.removed', ({ el, component }) => {
    //
})

Livewire.hook('morph.adding',  ({ el, component }) => {
    //
})

Livewire.hook('morph.added',  ({ el }) => {
    //
})

除了每个元素触发的事件外,每个 Livewire 组件还会触发 morphmorphed 事件:

js
Livewire.hook('morph',  ({ el, component }) => {
    // 在 `component` 中的子元素被 morph 之前运行(不包括部分 morphing)
})

Livewire.hook('morphed',  ({ el, component }) => {
    // 在 `component` 中的所有子元素被 morph 之后运行(不包括部分 morphing)
})

服务端 JavaScript 求值

除了直接在组件中执行 JavaScript 外,您还可以使用 js() 方法从服务端 PHP 代码求值 JavaScript 表达式。

这通常用于在执行服务端操作后执行某种客户端后续操作。

例如,以下是一个 post.create 组件,在文章保存到数据库后触发客户端警告对话框:

php
<?php // resources/views/components/post/⚡create.blade.php

use Livewire\Component;

new class extends Component {
    public $title = '';

    public function save()
    {
        // 将文章保存到数据库...

        $this->js("alert('文章已保存!')");
    }
};

JavaScript 表达式 alert('文章已保存!') 将在服务器上保存文章后在客户端执行。

您可以在表达式内访问当前组件的 $wire 对象:

php
$this->js('$wire.$refresh()');
$this->js('$wire.$dispatch("post-created", { id: ' . $post->id . ' })');

常见模式

以下是在实际应用中使用 JavaScript 与 Livewire 的一些常见模式。

集成第三方库

许多 JavaScript 库需要在元素添加到页面时进行初始化。使用组件脚本在组件加载时初始化库:

blade
<div>
    <div id="map" style="height: 400px;"></div>
</div>

@assets
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY"></script>
@endassets

<script>
    new google.maps.Map($wire.$el.querySelector('#map'), {
        center: { lat: {{ $latitude }}, lng: {{ $longitude }} },
        zoom: 12
    });
</script>

与 localStorage 同步

您可以使用 $watch 将组件状态与 localStorage 同步:

blade
<script>
    // 初始化时从 localStorage 加载
    if (localStorage.getItem('draft')) {
        $wire.content = localStorage.getItem('draft');
    }

    // 当值更改时保存到 localStorage
    $wire.$watch('content', (value) => {
        localStorage.setItem('draft', value);
    });
</script>

使用 @js 指令

如果您需要输出 PHP 数据以直接在 JavaScript 中使用,可以使用 @js 指令。

blade
<script>
    let posts = @js($posts)

    // "posts" 现在将是来自 PHP 的文章数据的 JavaScript 数组。
</script>

最佳实践

组件脚本 vs 全局脚本

在以下情况下使用组件脚本:

  • JavaScript 特定于该组件的功能
  • 您需要访问 $wire 或组件特定的数据
  • 代码应在每次组件加载时运行

在以下情况下使用全局脚本:

  • 注册自定义指令或钩子
  • 设置全局事件监听器
  • 初始化应用范围的 JavaScript

避免内存泄漏

在组件脚本中添加事件监听器时,Livewire 会在组件移除时自动清理它们。但是,如果您使用全局拦截器或钩子,请确保在适当时进行清理:

js
// 组件级别 - 自动清理 ✓
$wire.intercept(({ onSend }) => {
    onSend(() => console.log('正在发送...'));
});

// 全局级别 - 在整个页面生命周期内存在
Livewire.interceptMessage(({ onSend }) => {
    onSend(() => console.log('正在发送...'));
});

调试技巧

从浏览器控制台访问组件:

js
// 获取页面上的第一个组件
let $wire = Livewire.first()

// 检查组件状态
console.log($wire.count)

// 调用方法
$wire.increment()

监控所有请求:

js
Livewire.interceptRequest(({ onSend }) => {
    onSend(() => {
        console.log('请求已发送:', Date.now());
    });
});

查看组件快照:

js
let component = Livewire.first().__instance()
console.log(component.snapshot)

性能考虑

  • 在不应被 Livewire 的 DOM morphing 触及的元素上使用 wire:ignore
  • 使用 wire:model.debounce 或 JavaScript 防抖来处理昂贵的操作
  • 对于不立即可见的组件使用延迟加载(lazy 参数)
  • 考虑使用 islands 来隔离独立更新的区域

另请参阅

  • 样式 — 为组件添加作用域 CSS
  • Alpine — 使用 Alpine 实现客户端交互
  • 操作 — 在组件中创建 JavaScript 操作
  • 属性 — 使用 $wire 从 JavaScript 访问属性
  • 事件 — 在 JavaScript 中分发和监听事件

参考

在扩展 Livewire 的 JavaScript 系统时,了解您可能遇到的不同对象非常重要。

以下是 Livewire 每个相关内部属性的详尽参考。

提醒一下,普通的 Livewire 用户可能永远不会与这些交互。这些对象大多数可用于 Livewire 的内部系统或高级用户。

$wire 对象

给定以下通用的 Counter 组件:

php
<?php

namespace App\Livewire;

use Livewire\Component;

class Counter extends Component
{
    public $count = 1;

    public function increment()
    {
        $this->count++;
    }

    public function render()
    {
        return view('livewire.counter');
    }
}

Livewire 以对象形式暴露服务端组件的 JavaScript 表示,通常称为 $wire

js
let $wire = {
    // 所有组件公共属性都可以直接在 $wire 上访问...
    count: 0,

    // 所有公共方法都在 $wire 上暴露和可调用...
    increment() { ... },

    // 如果存在,访问父组件的 `$wire` 对象...
    $parent,

    // 访问 Livewire 组件的根 DOM 元素...
    $el,

    // 访问当前 Livewire 组件的 ID...
    $id,

    // 通过名称获取属性的值...
    // 用法: $wire.$get('count')
    $get(name) { ... },

    // 通过名称设置组件上的属性...
    // 用法: $wire.$set('count', 5)
    $set(name, value, live = true) { ... },

    // 切换布尔属性的值...
    $toggle(name, live = true) { ... },

    // 调用方法...
    // 用法: $wire.$call('increment')
    $call(method, ...params) { ... },

    // 定义 JavaScript 操作...
    // 用法: $wire.$js('increment', () => { ... })
    // 用法: $wire.$js.increment = () => { ... }
    $js(name, callback) { ... },

    // [已弃用] Entangle - 您可能不需要这个。
    // 改用 $wire 直接访问属性。
    // 用法: <div x-data="{ count: $wire.$entangle('count') }">
    $entangle(name, live = false) { ... },

    // 监视属性值的变化...
    // 用法: Alpine.$watch('count', (value, old) => { ... })
    $watch(name, callback) { ... },

    // 通过向服务器发送消息来刷新组件
    // 以重新渲染 HTML 并将其交换到页面中...
    $refresh() { ... },

    // 与上面的 `$refresh` 相同。只是一个更技术性的名称...
    $commit() { ... }, // $refresh 的别名

    // 监听从此组件或其子组件分发的事件...
    // 用法: $wire.$on('post-created', () => { ... })
    $on(event, callback) { ... },

    // 监听从此组件或请求触发的生命周期钩子...
    // 用法: $wire.$hook('message.sent', () => { ... })
    $hook(name, callback) { ... },

    // 从此组件分发事件...
    // 用法: $wire.$dispatch('post-created', { postId: 2 })
    $dispatch(event, params = {}) { ... },

    // 向另一个组件分发事件...
    // 用法: $wire.$dispatchTo('dashboard', 'post-created', { postId: 2 })
    $dispatchTo(otherComponentName, event, params = {}) { ... },

    // 仅向此组件分发事件,不向其他组件分发...
    $dispatchSelf(event, params = {}) { ... },

    // 直接向组件上传文件的 JS API
    // 而不是通过 `wire:model`...
    $upload(
        name, // 属性名称
        file, // File JavaScript 对象
        finish = () => { ... }, // 上传完成时运行...
        error = () => { ... }, // 上传过程中触发错误时运行...
        progress = (event) => { // 上传进度时运行...
            event.detail.progress // 1-100 的整数...
        },
    ) { ... },

    // 同时上传多个文件的 API...
    $uploadMultiple(name, files, finish, error, progress) { },

    // 在临时上传但未保存后移除上传...
    $removeUpload(name, tmpFilename, finish, error) { ... },

    // 为此组件实例注册 action 拦截器
    // 用法: $wire.intercept(({ action, onSend, onCancel, onSuccess, onError, onFailure, onFinish }) => { ... })
    // 或限定到特定 action: $wire.intercept('save', ({ action, onSuccess }) => { ... })
    intercept(actionOrCallback, callback) { ... },

    // intercept 的别名
    interceptAction(actionOrCallback, callback) { ... },

    // 为此组件实例注册 message 拦截器
    // 用法: $wire.interceptMessage(({ message, cancel, onSend, onCancel, onSuccess, onError, onFailure, onFinish }) => { ... })
    // 或限定到特定 action: $wire.interceptMessage('save', callback)
    interceptMessage(actionOrCallback, callback) { ... },

    // 为此组件实例注册 request 拦截器
    // 用法: $wire.interceptRequest(({ request, onSend, onCancel, onSuccess, onError, onFailure, onFinish }) => { ... })
    // 或限定到特定 action: $wire.interceptRequest('save', callback)
    interceptRequest(actionOrCallback, callback) { ... },

    // 获取底层的 "component" 对象...
    __instance() { ... },
}

您可以在 Livewire 关于在 JavaScript 中访问属性的文档 中了解更多关于 $wire 的信息。

snapshot 对象

在每个网络请求之间,Livewire 将 PHP 组件序列化为可以在 JavaScript 中使用的对象。此快照用于将组件反序列化回 PHP 对象,因此具有内置的防篡改机制:

js
let snapshot = {
    // 组件的序列化状态(公共属性)...
    data: { count: 0 },

    // 关于组件的长期信息...
    memo: {
        // 组件的唯一 ID...
        id: '0qCY3ri9pzSSMIXPGg8F',

        // 组件的名称。例如 <livewire:[name] />
        name: 'counter',

        // 最初加载组件的网页的 URI、方法和区域设置。
        // 这用于将原始请求的任何中间件
        // 重新应用到后续组件更新请求(消息)...
        path: '/',
        method: 'GET',
        locale: 'en',

        // 任何嵌套的"子"组件列表。以内部模板 ID 为键,
        // 组件 ID 为值...
        children: [],

        // 此组件是否"延迟加载"...
        lazyLoaded: false,

        // 上次请求期间抛出的任何验证错误列表...
        errors: [],
    },

    // 此快照的安全加密哈希。这样,
    // 如果恶意用户篡改快照以访问服务器上
    // 不属于他们的资源,校验和验证将失败
    // 并抛出错误...
    checksum: '1bc274eea17a434e33d26bcaba4a247a4a7768bd286456a83ea6e9be2d18c1e7',
}

component 对象

页面上的每个组件都有一个相应的 component 对象在幕后跟踪其状态并暴露其底层功能。这比 $wire 更深一层。它仅用于高级用法。

以下是上述 Counter 组件的实际 component 对象,JS 注释中描述了相关属性:

js
let component = {
    // 组件的根 HTML 元素...
    el: HTMLElement,

    // 组件的唯一 ID...
    id: '0qCY3ri9pzSSMIXPGg8F',

    // 组件的"名称"(<livewire:[name] />)...
    name: 'counter',

    // 最新的"效果"对象。效果是服务器
    // 往返的"副作用"。包括重定向、文件下载等...
    effects: {},

    // 组件最后已知的服务端状态...
    canonical: { count: 0 },

    // 组件的可变数据对象,表示其
    // 实时客户端状态...
    ephemeral: { count: 0 },

    // `this.ephemeral` 的响应式版本。对此对象的更改
    // 将被 AlpineJS 表达式捕获...
    reactive: Proxy,

    // 通常在 Alpine 表达式中用作 `$wire` 的 Proxy 对象。
    // 这旨在为 Livewire 组件提供
    // 友好的 JS 对象接口...
    $wire: Proxy,

    // 任何嵌套的"子"组件列表。以内部模板 ID 为键,
    // 组件 ID 为值...
    children: [],

    // 此组件的最后已知"快照"表示。
    // 快照从服务端组件获取,用于
    // 在后端重新创建 PHP 对象...
    snapshot: {...},

    // 上述快照的未解析版本。这用于在下次往返时
    // 发送回服务器,因为 JS 解析会干扰 PHP 编码,
    // 这通常会导致校验和不匹配。
    snapshotEncoded: '{"data":{"count":0},"memo":{"id":"0qCY3ri9pzSSMIXPGg8F","name":"counter","path":"\/","method":"GET","children":[],"lazyLoaded":true,"errors":[],"locale":"en"},"checksum":"1bc274eea17a434e33d26bcaba4a247a4a7768bd286456a83ea6e9be2d18c1e7"}',
}

message 负载

当在浏览器中对 Livewire 组件执行操作时,会触发网络请求。该网络请求包含一个或多个组件以及服务器的各种指令。在内部,这些组件网络负载称为"消息"。

"消息"表示当组件需要更新时从前端发送到后端的数据。组件在前端渲染和操作,直到执行需要它将其状态和更新发送到后端的操作。

您将在浏览器 DevTools 的网络选项卡中或 Livewire 的 JavaScript 钩子 中看到此模式:

js
let message = {
    // 快照对象...
    snapshot: { ... },

    // 要在服务器上更新的属性的键值对列表...
    updates: {},

    // 要在服务端调用的方法(带参数)数组...
    calls: [
        { method: 'increment', params: [] },
    ],
}