Vue 3 中的 readonly 和 shallowReadonly:保护数据不被修改

Vue 3 中的 readonly 和 shallowReadonly:保护数据不被修改

在开发中,我们经常需要共享数据,但是我们并不希望共享的数据被意外修改;Vue3提供了readonly和shallowReadonly这两个API,用于创建只读的响应式对象。它们可以包装ref,reactive或者其他的响应式对象,返回一个只读的代理;

1.readonly深度只读

readonly会被传入的响应式数据转换为深度只读的代理。这个代理的任何修改都会被警告

vue 复制代码
<template>
  <h2>{{ copy }}</h2>
  <button @click="ChangeCopy">修改年龄</button>
</template>
<script setup>
import { readonly, reactive } from 'vue';
const original = reactive({
  user: {
    name: 'Alice',
    age: 20
  }
})

const copy = readonly(original)

function ChangeCopy() {
  copy.user.age = 22;
}

</script>
<style></style>

readonly在实际中有什么作用呢?

比如父组件传递配置给子组件,但是禁止子组件修改

vue 复制代码
//父组件
<template>
  <div>
    <h1>系统配置</h1>
    <p>主题:{{ config.theme }}</p>
    <p>语言:{{ config.language }}</p>
    <Child :config="readonlyConfig" />
  </div>
</template>
<script setup>
import { readonly, reactive } from 'vue';
import Child from './Child.vue';
//可修改的系统配置
const config = reactive({
  theme: 'dark',
  language: 'zh-CN',
  features: {
    bata: true,
    experimental: false
  }
})

//创建只读版本传递给子组件
const readonlyConfig = readonly(config);

//父组件可以正常修改配置
function updateConfig() {
  config.theme = 'light',
    config.language = 'en-US'
}


</script>
<style></style>
vue 复制代码
//子组件
<template>
    <div>
        <h3>子组件-只读配置</h3>
        <p>主题:{{ config.theme }}</p>
        <p>语言:{{ config.language }}</p>
        <button @click="tryModify">尝试修改配置</button>
    </div>
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps(['config'])
function tryModify() {
    props.config.theme = 'light'
}
</script>

2.shallowReadonly渐层只读

shallowReadonly只将对象的顶层属性设为只读,嵌套的对象仍然是可变的

vue 复制代码
<template>
  <h2>{{ original }}</h2>
  <button @click="changeCount">修改顶层属性count</button>
  <button @click="changeName">修改嵌套属性name</button>
</template>
<script setup>
import { shallowReadonly, reactive } from 'vue'

const original = reactive({
  count: 0,
  user: { name: 'Alice' }
})

const copy = shallowReadonly(original)

// 修改顶层属性会失败
function changeCount() {
  copy.count = 1  // ❌ 警告
}

function changeName() {
  // 修改嵌套属性允许
  copy.user.name = 'Bob'  // ✅ 有效,且会触发响应式更新
}


</script>
<style></style>

其实shallowReadonly在现实中用的并不多,这里还展示一种实际使用案例,比如一个表单的例子,表单的字段不可能改变,因为是固定的,每个人都一样,但是表单的值是可以更改的

vue 复制代码
<template>
  <div>
    <form @submit.prevent="submitForm">
      <input v-model="formData.name" placeholder="姓名" />
      <input v-model="formData.email" placeholder="邮箱" />
      <button type="submit">提交</button>
    </form>
    <button @click="resetForm">重置表单</button>
  </div>
</template>

<script setup>
import { reactive, shallowReadonly } from 'vue'

// 表单数据结构(可修改)
const formData = reactive({
  name: '',
  email: '',
  // 假设有大量其他字段
})

// 对外暴露只读的结构(防止外部意外替换整个对象)
// 但内部字段值仍可修改
const readonlyForm = shallowReadonly(formData)

// 外部组件如果尝试修改顶层属性会失败,但修改 name/email 仍有效
function resetForm() {
  // 尝试直接替换对象(会失败)
  // readonlyForm = { name: '', email: '' }  // ❌ 不允许
  // 正确做法:通过原对象修改
  formData.name = ''
  formData.email = ''
}

function submitForm() {
  // 提交时使用 readonlyForm 或者 formData 都可以
  console.log('提交数据:', readonlyForm)
}
</script>
相关推荐
仿生狮子1 小时前
✂️ Nuxt 最简单的字体裁剪工具:Fontize
javascript·vue.js·nuxt.js
魔力女仆4 小时前
分享一个 JS 鼠标跟随贪吃蛇背景库
开发语言·javascript·计算机外设
别惊醒渔人6 小时前
Vue3 Diff 优化:最长递增子序列 LIS
前端·javascript·vue.js
Larcher6 小时前
从“加载模型”界面到端侧推理:拆解一个 React + WebGPU 大模型 Demo
javascript·后端
Larcher7 小时前
从状态快照到惰性初始化:读懂 React useState 的三个关键场景
javascript·人工智能·后端
Hilaku8 小时前
工作 5 年后,决定你薪资上限的究竟是什么?
前端·javascript·程序员
weixin_BYSJ19879 小时前
springboot校园自习室管理小程序---附源码32142
java·javascript·spring boot·python·django·flask·php
gis开发之家9 小时前
《Vue3 从入门到大神40篇》Vue3 源码详解(十):diff 算法全解析 —— 为什么 Vue3 比 Vue2 更快?
javascript·算法·typescript·前端框架·vue3·vue3源码
用户831348593069810 小时前
Vue+Three.js实现PCB电路板3D交互:元器件点击高亮、部件显隐、模型自动旋转
vue.js·webgl·three.js
海带紫菜菠萝汤11 小时前
WebCodecs API 实战:浏览器原生视频编解码的原理与性能测试
前端·javascript·音视频·视频编解码