首页 > 编程笔记 > JavaScript笔记
阅读:252
Vue3 toRaw()和markRaw()的用法(附带实例)
在 Vue 程序中,如果我们想得到一个 reactive 对象内部包含的原始对象,就可以选择使用 toRaw() 函数。如果我们不想让一个原始对象包装生成 reactive 响应式对象,就可以选择使用 markRaw() 函数。
toRaw() 函数接收的参数为一个 reactive 对象,返回值为内部包含的整个原始对象。
markRaw() 函数接收的参数为一个原始对象,返回值还是这个原始对象,但其被添加了不能转换为 reactive 对象的标识属性 __v_skip,该值为 true。当我们将这个对象传入 reactive 函数时,返回的就不是代理对象了,而是参数对象本身。也就是说,它并不是响应式对象。
下面通过代码来演示 toRaw() 与 markRaw() 函数的使用方法:

图 1 运行代码后的页面效果
在上面的代码中先定义了一个 reactive 对象 state,然后在“测试toRaw”按钮的点击回调中,调用 toRaw() 函数,并传入 state 对象,得到的就是 state 对象中包含的原始对象。控制台输出如下图所示:
接着定义了一个原始对象 person2,调用 markRaw() 函数,并传入 person2 对象,返回的还是 person2 对象。只是对象被添加了 __v_skip 为 true 的属性,该属性用来标识此对象不能生成 reactive 对象。控制台输出如下图所示:

图 3 控制台输出(2)
随后调用 reactive() 函数,传入带 __v_skip 属性的对象,就不再返回一个代理对象,而是返回传入的对象本身,这就意味着此对象不能再进行响应式处理。
我们在 setup() 函数的返回对象中添加了 state2,模板可以通过 state2 读取里面任意层级的属性进行显示。但在“测试markRaw”按钮的点击回调 test2 中,通过 state2 来更新内部属性数据,页面不会自动更新,但通过控制台打印输出可以发现数据确实已经变了,如下图所示。

图 4 控制台输出(3)
这也就说明了,被 markRaw() 函数处理的对象,不能生成响应式的 reactive 对象。
那么,在什么情况下需要使用 toRaw() 与 markRaw() 函数呢?当我们想得到 reactive 对象中包含的整个原始对象时,toRaw() 函数就是一个不错的选择。当我们为其他模块提供一个包含多个数据的对象时,如果我们不需要,也不希望外部使用者将其处理为响应式对象,就可以先使用 markRaw() 函数来处理这个对象后再返回它。
toRaw() 函数接收的参数为一个 reactive 对象,返回值为内部包含的整个原始对象。
markRaw() 函数接收的参数为一个原始对象,返回值还是这个原始对象,但其被添加了不能转换为 reactive 对象的标识属性 __v_skip,该值为 true。当我们将这个对象传入 reactive 函数时,返回的就不是代理对象了,而是参数对象本身。也就是说,它并不是响应式对象。
下面通过代码来演示 toRaw() 与 markRaw() 函数的使用方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>toRaw 与 markRaw 函数</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.40/vue.global.js"></script>
</head>
<body>
<div id="app">
<p>state.name: {{ state.name }}</p>
<p>state.addr.city: {{ state.addr.city }}</p>
<button @click="test1">测试 toRaw</button>
<hr />
<p>state2.name: {{ state2.name }}</p>
<p>state2.addr.city: {{ state2.addr.city }}</p>
<button @click="test2">测试 markRaw</button>
</div>
<script>
const { createApp, reactive, toRaw, markRaw } = Vue;
createApp({
setup() {
// 定义 reactive 对象
const state = reactive({
name: '张三',
addr: {
city: '北京',
},
});
// 测试使用 toRaw 函数
const test1 = () => {
// 通过 toRaw 函数得到 reactive 对象中包含的原始对象
const rawPerson = toRaw(state);
console.log(rawPerson);
};
// 原始对象
const person2 = {
name: '李四',
addr: {
city: '上海',
},
};
// 标记一个原始对象不能生成 reactive 对象,并返回这个对象
const markPerson2 = markRaw(person2);
console.log(markPerson2); // 多了一个 __v_skip 为 true 的属性
// 对 markRaw 函数的对象进行 reactive 处理,会被原样返回,它不是响应式的
const state2 = reactive(markPerson2);
console.log(state2);
console.log(markPerson2 === person2, state2 === markPerson2);
// 测试更新 markRaw 函数的 reactive 对象,页面不会自动更新
const test2 = () => {
state2.name += '---1';
state2.addr.city += '---1';
console.log(state2.name, state2.addr.city);
};
return {
state,
state2,
test1,
test2,
};
},
}).mount('#app');
</script>
</body>
</html>
运行代码后的页面效果如下图所示:
图 1 运行代码后的页面效果
在上面的代码中先定义了一个 reactive 对象 state,然后在“测试toRaw”按钮的点击回调中,调用 toRaw() 函数,并传入 state 对象,得到的就是 state 对象中包含的原始对象。控制台输出如下图所示:

接着定义了一个原始对象 person2,调用 markRaw() 函数,并传入 person2 对象,返回的还是 person2 对象。只是对象被添加了 __v_skip 为 true 的属性,该属性用来标识此对象不能生成 reactive 对象。控制台输出如下图所示:

图 3 控制台输出(2)
随后调用 reactive() 函数,传入带 __v_skip 属性的对象,就不再返回一个代理对象,而是返回传入的对象本身,这就意味着此对象不能再进行响应式处理。
我们在 setup() 函数的返回对象中添加了 state2,模板可以通过 state2 读取里面任意层级的属性进行显示。但在“测试markRaw”按钮的点击回调 test2 中,通过 state2 来更新内部属性数据,页面不会自动更新,但通过控制台打印输出可以发现数据确实已经变了,如下图所示。

图 4 控制台输出(3)
这也就说明了,被 markRaw() 函数处理的对象,不能生成响应式的 reactive 对象。
那么,在什么情况下需要使用 toRaw() 与 markRaw() 函数呢?当我们想得到 reactive 对象中包含的整个原始对象时,toRaw() 函数就是一个不错的选择。当我们为其他模块提供一个包含多个数据的对象时,如果我们不需要,也不希望外部使用者将其处理为响应式对象,就可以先使用 markRaw() 函数来处理这个对象后再返回它。
ICP备案:
公安联网备案: