跳转至

Persist 插件

Alpine 的 Persist 插件允许你在页面加载之间持久化 Alpine 状态。

这对于持久化搜索过滤器、活动选项卡以及其他功能非常有用,这些情况下用户在刷新或离开并重新访问页面时,其配置被重置会感到沮丧。

安装

你可以通过 <script> 标签引入或通过 NPM 安装来使用此插件:

通过 CDN

你可以将此插件的 CDN 构建版本作为 <script> 标签引入,只需确保在 Alpine 核心 JS 文件之前引入。

<!-- Alpine 插件 -->
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/[email protected]/dist/cdn.min.js"></script>

<!-- Alpine 核心 -->
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>

通过 NPM

你可以从 NPM 安装 Persist 以在打包中使用:

npm install @alpinejs/persist

然后从你的打包工具中初始化它:

import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'

Alpine.plugin(persist)

...

$persist

使用此插件的主要 API 是 $persist 魔法方法。

你可以像下面这样将 x-data 中的任何值用 $persist 包裹,以在页面加载之间持久化其值:

<div x-data="{ count: $persist(0) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>
</div>

在上面的示例中,因为我们用 $persist() 包裹了 0,Alpine 现在会拦截对 count 所做的更改,并在页面加载之间持久化它们。

你可以亲自尝试:在上面的示例中增加"count",然后刷新此页面,观察"count"是否保持其状态而不是重置为"0"。

它是如何工作的?

如果一个值用 $persist 包裹,在初始化时 Alpine 会为该值注册自己的监听器。现在每当该值因任何原因发生变化时,Alpine 都会将新值存储在 localStorage 中。

现在当页面重新加载时,Alpine 会检查 localStorage(使用属性名称作为键)以查找值。如果找到了,它会立即从 localStorage 设置属性值。

你可以通过打开浏览器开发者工具的 localStorage 查看器来观察此行为:

Chrome devtools showing the localStorage view with count set to 0

你会注意到,只要访问此页面,Alpine 就已经在 localStorage 中设置了"count"的值。你还会注意到它将属性名"count"添加了前缀 _x_,作为命名空间这些值的方式,使 Alpine 不会与使用 localStorage 的其他工具冲突。

现在更改以下示例中的"count",并观察 Alpine 对 localStorage 所做的更改:

<div x-data="{ count: $persist(0) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>
</div>

$persist 适用于原始值以及数组和对象。 然而,值得注意的是,当变量的类型发生变化时,localStorage 必须被清除。
根据前面的示例,如果我们将 count 改为 $persist({ value: 0 }) 的值,那么必须清除 localStorage 或重命名变量'count'。

设置自定义键

默认情况下,Alpine 使用 $persist(...) 被分配到的属性键(在上述示例中为"count")。

考虑这样一种场景:你有多个 Alpine 组件分布在多个页面上,甚至在同一个页面上,它们都使用"count"作为属性键。

Alpine 将无法区分这些组件。

在这些情况下,你可以使用 .as 修饰符为任何持久化值设置自己的自定义键,如下所示:

<div x-data="{ count: $persist(0).as('other-count') }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>
</div>

现在 Alpine 将使用键"other-count"来存储和检索上面的"count"值。

以下是 Chrome Devtools 的视图,供你亲自查看:

Chrome devtools showing the localStorage view with count set to 0

使用自定义存储

默认情况下,数据保存到 localStorage,它没有过期时间,即使在页面关闭后也会保持。

考虑这样一种场景:你希望在用户关闭标签页时清除数据。在这种情况下,你可以使用 .using 修饰符将数据持久化到 sessionStorage,如下所示:

<div x-data="{ count: $persist(0).using(sessionStorage) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>
</div>

你也可以定义自己的自定义存储对象,暴露一个 getItem 函数和一个 setItem 函数。例如,你可以决定使用会话 cookie 作为存储:

<script>
    window.cookieStorage = {
        getItem(key) {
            let cookies = document.cookie.split(";");
            for (let i = 0; i < cookies.length; i++) {
                let cookie = cookies[i].split("=");
                if (key == cookie[0].trim()) {
                    return decodeURIComponent(cookie[1]);
                }
            }
            return null;
        },
        setItem(key, value) {
            document.cookie = key+' = '+encodeURIComponent(value)
        }
    }
</script>

<div x-data="{ count: $persist(0).using(cookieStorage) }">
    <button x-on:click="count++">Increment</button>

    <span x-text="count"></span>
</div>

将 $persist 与 Alpine.data 一起使用

如果你想将 $persistAlpine.data 一起使用,你需要使用标准函数而不是箭头函数,这样 Alpine 才能在初始评估组件作用域时绑定自定义的 this 上下文。

Alpine.data('dropdown', function () {
    return {
        open: this.$persist(false)
    }
})

使用 Alpine.$persist 全局

Alpine.$persist 是全局暴露的,因此可以在 x-data 上下文之外使用。这对于持久化来自其他源(如 Alpine.store)的数据很有用。

Alpine.store('darkMode', {
    on: Alpine.$persist(true).as('darkMode_on')
});