在Pinia中如何持久化存储带函数的对象

在使用 Pinia 进行状态管理时,常规方法难以直接持久化存储包含函数的对象。因为 JSON.stringify()在序列化对象时会忽略函数。本文将介绍一种自定义的解决方案,实现包含函数对象的持久化。

1. 安装依赖

确保项目中已经安装了 Pinia。如果没有安装,可以通过 npm 进行安装:

1
npm install pinia

2. 自定义持久化逻辑

实现自定义的持久化逻辑,通过将函数序列化为字符串存储,在恢复时再转换回函数。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { defineStore } from "pinia";

// 自定义持久化逻辑
const loadState = () => {
const state = localStorage.getItem("myStore");
if (state) {
const parsedState = JSON.parse(state);
// 将存储的函数字符串转换回函数
if (
parsedState.myObject &&
typeof parsedState.myObject.sayHello === "string"
) {
parsedState.myObject.sayHello = new Function(
`return ${parsedState.myObject.sayHello}`
)();
}
return parsedState;
}
return null;
};

const saveState = (state) => {
// 将函数转换为字符串存储
const stateToSave = { ...state };
if (
stateToSave.myObject &&
typeof stateToSave.myObject.sayHello === "function"
) {
stateToSave.myObject.sayHello = stateToSave.myObject.sayHello.toString();
}
localStorage.setItem("myStore", JSON.stringify(stateToSave));
};

// 定义包含函数的对象
const myObjectWithFunction = {
message: "Hello from Pinia!",
sayHello: function () {
console.log(this.message);
},
};

// 定义Pinia存储
export const useMyStore = defineStore("myStore", {
state: () => {
const savedState = loadState();
return (
savedState || {
myObject: myObjectWithFunction,
}
);
},
actions: {
updateMessage(newMessage) {
this.myObject.message = newMessage;
saveState(this.$state);
},
},
// 在存储更新时调用保存逻辑
onBeforeUpdate: () => {
saveState(useMyStore().$state);
},
});

3. 在组件中使用

在 Vue 3 组件中使用上述定义的 Pinia 存储。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<button @click="callFunctionInObject">Call Function in Object</button>
<input v-model="newMessage" placeholder="Enter new message" />
<button @click="updateMessage">Update Message</button>
</div>
</template>

<script setup>
import { ref } from "vue";
import { useMyStore } from "./store";

const store = useMyStore();
const newMessage = ref("");

const callFunctionInObject = () => {
store.myObject.sayHello();
};

const updateMessage = () => {
store.updateMessage(newMessage.value);
};
</script>

注意事项

  1. 安全风险:使用new Function()存在安全风险,如果存储的函数字符串来自不可信源,可能会执行恶意代码。
  2. 复杂场景:函数序列化可能无法处理所有复杂情况,如函数内部引用了外部变量。

通过上述方法,我们能够在 Pinia 中实现包含函数对象的持久化存储,解决常规持久化方案无法处理函数的问题。

GIT贮藏

在 Git 里,贮藏(stash)能够把你工作目录里未提交的修改保存起来,让你可以在之后恢复这些修改。

1. 检查当前工作目录状态

在建立贮藏之前,你可以使用以下命令查看当前工作目录的状态:

1
git status

该命令会显示哪些文件被修改、添加或者删除。

2. 创建贮藏

若你要把所有未提交的修改(包括已暂存和未暂存的)保存到一个贮藏中,可以使用下面的命令:

1
git stash save "可选的贮藏描述信息"

例如:

1
git stash save "临时保存未完成的功能修改"

如果你仅想贮藏已暂存的文件,可使用:

1
git stash push -p

然后按提示选择要贮藏的修改。

3. 查看贮藏列表

创建贮藏之后,你可以使用以下命令查看贮藏列表:

1
git stash list

输出结果可能如下:

1
stash@{0}: On master: 临时保存未完成的功能修改

4. 恢复贮藏

若你想恢复最近一次的贮藏,可以使用:

1
git stash apply

要是你想恢复特定的贮藏,可指定贮藏的编号,例如恢复stash@{0}

1
git stash apply stash@{0}

恢复贮藏后,该贮藏依旧存在于贮藏列表中。若你想在恢复贮藏的同时将其从贮藏列表里移除,可以使用pop命令:

1
git stash pop

5. 删除贮藏

如果你想删除某个贮藏,可以使用以下命令:

1
git stash drop stash@{0}

若要删除所有贮藏,可使用:

1
git stash clear

passive

在 JavaScript 中,passive 是一个布尔值,用于指定事件监听器是否应该被标记为“被动”的。这个属性主要用于触摸事件(如 touchstarttouchmovetouchendtouchcancel)和滚轮事件(如 wheel)。

什么是被动事件监听器?

被动事件监听器是一种不会阻止浏览器默认行为的异步事件监听器。默认情况下,事件监听器是同步的,这意味着它们会阻止浏览器执行默认行为,直到事件处理程序执行完毕。但是,被动事件监听器不会阻止浏览器执行默认行为,从而提高了滚动性能。

如何使用 passive 选项?

你可以通过在事件监听器的 addEventListener 方法中设置 passive 选项来指定事件监听器是否应该被标记为被动。

1
2
3
4
5
6
7
element.addEventListener(
"touchstart",
function (event) {
// 处理触摸事件
},
{ passive: true }
);

在上面的例子中,我们为 touchstart 事件添加了一个被动的事件监听器。这意味着浏览器可以自由地执行默认的触摸行为,而不会等待事件处理程序执行完毕。

注意事项

  • 被动事件监听器只能用于触摸事件和滚轮事件。对于其他事件,passive 选项将被忽略。
  • 如果事件处理程序需要阻止默认行为,那么它不能被标记为被动。否则,浏览器将无法执行默认行为。
  • 被动事件监听器可以提高滚动性能,但它们可能会影响其他事件的处理。因此,在使用被动事件监听器时,要确保你的代码可以正确地处理所有事件。

示例

以下是一个使用被动事件监听器的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<title>Passive Event Listener Example</title>
</head>
<body>
<div id="scrollable" style="width: 200px; height: 200px; overflow: scroll;">
<div style="height: 1000px;"></div>
</div>

<script>
const scrollable = document.getElementById("scrollable");

scrollable.addEventListener(
"scroll",
function (event) {
console.log("Scrolling...");
},
{ passive: true }
);
</script>
</body>
</html>

在上面的例子中,我们为 scroll 事件添加了一个被动的事件监听器。这意味着浏览器可以自由地执行滚动行为,而不会等待事件处理程序执行完毕。