问问题是学习最好的方式
// 父组件 SceneModel
<InfoPanel :pannel="toolInfo" />
// 子组件 SceneInfoPanel
<div class="grid-item" v-for="(item, index) in props.pannel.content" :key="index">
<div class="grid-item-title">{{ t(item.title) }}</div>
<template v-if="item.editable">
<el-input
class="editable-item"
:input-style="inputStyle"
size="small"
v-model="item.value"
:placeholder="item.placeholder || ''"
></el-input>
</template>
<div v-else class="grid-item-value">{{ item.value == 0 ? 0 : item.value || '--' }}</div>
</div>
子组件这里el-input修改props.pannel.content之后是如何保存的呢?
props不是不允许修改吗?
父组件又是如何接收得呢?
1. el-input
修改 props.pannel.content
是如何保存的?props 不是不允许修改吗?
现象
在 SceneInfoPanel.vue 里这样用:
<el-input
class="editable-item"
:input-style="inputStyle"
size="small"
v-model="item.value"
:placeholder="item.placeholder || ''"
/>
这里 item
来自 props.pannel.content
,而 props
理论上是只读的。
实际原因
- Vue 的“只读”是针对
props
对象本身,即你不能直接赋值props.pannel = xxx
。 - 但如果
props.pannel
里传的是一个对象或数组(引用类型),你可以修改它的属性(如props.pannel.content[0].value = ...
),Vue 不会阻止。 - 这种“间接修改”其实是反模式,但 Vue3 没有严格禁止(Vue2 的
propsData
也一样)。
所以:
- 你通过
v-model="item.value"
实际上是直接改了props.pannel.content
里的数据。 - 只要父组件传进来的
pannel
是响应式的(如reactive
或ref
),父组件也能感知到这些变化。
2. SceneModel
又是如何接收到的?
在 SceneModel.vue 里:
<InfoPanel :pannel="toolInfo" />
toolInfo
是reactive
的对象,包含content
等属性。- 你在
SceneInfoPanel
里通过v-model="item.value"
改变了toolInfo.content
的内容。 - 因为
toolInfo
是响应式的,SceneModel
里可以直接读取到最新的内容(如toolInfo.content
),数据是同步的。
总结
- 你没有直接赋值 props,只是修改了 props 里的对象属性,Vue 没有阻止。
- 父组件传递的对象是响应式的,子组件的修改会同步到父组件。
- 这种写法虽然常见,但更推荐用事件/emit通知父组件修改数据,以避免维护上的混乱。
推荐写法(更规范)
- 子组件用
emit('update:value', newValue)
通知父组件修改数据。 - 父组件用
v-model:value="xxx"
实现真正的单向数据流。
现在的写法能用,属于 Vue 的“引用透传”特性,建议后续优化为事件驱动的数据流。