Vue3中通过Prop传值至子组件,编辑后无法保存问题求助
问题描述
希望将值传入子组件,由子组件独立执行保存操作,父组件无需相关逻辑。目前已成功传入对象,但无法保存更新后的内容。已知props是只读的,尝试复制props但仅维护了一个数据模型,不理解为何需要向父组件emit后再传回子组件,寻求解决方案。
父组件代码
<template> <div v-show="isOpened"> <EditModal @toggle="closeModal" @update:todo="submitUpdate($event)" :updatedText="editText" :todo="modalPost" /> </div> </template> <script setup lang="ts"> import Post from "../components/Post.vue"; import { api } from "../lib/api"; import { ref } from "vue"; import { onMounted } from "vue-demi"; import EditModal from "../components/EditModal.vue"; const postArr = ref(''); const message = ref(''); let isOpened = ref(false); let modalPost = ref(''); let editText = ref(''); function closeModal() { isOpened.value = false } function openModal(value: string) { isOpened.value = true modalPost.value = value } // call posts so the table loads updated item function submitUpdate(value: any) { console.log("called update in parent " + value) editText.value = value posts() } </script>
子组件EditModal代码
<template> <div> <div> <textarea id="updateTextArea" rows="10" :value="props.todo.post"></textarea> </div> <!-- Modal footer --> <div> <button data-modal-toggle="defaultModal" type="button" @click="update(props.todo.blogId, props.todo.post)">Save</button> </div> </div> </template> <script lang="ts" setup> import { api } from "../lib/api"; import { reactive, ref } from "vue"; const props = defineProps({ todo: String, updatedText: String, }) const emit = defineEmits( ['toggle','update:todo'] ); function setIsOpened(value: boolean) { emit('toggle', value); } function update(id: string, value: string) { console.log('the value ' + value) try { api.updateBlog(id, value).then( res => { emit('update:todo', value) emit('toggle', false); }) } catch (e) { console.log('Error while updating post: '+ e) } } </script>
解决方案
核心问题是子组件未维护独立的编辑状态,提交时用的是原始props值而非用户编辑后的内容。要实现子组件独立完成编辑保存,按以下步骤修改:
1. 子组件修改(核心调整)
<template> <div> <div> <!-- 用v-model绑定本地编辑变量,实时同步输入内容 --> <textarea id="updateTextArea" rows="10" v-model="localTodo.post"></textarea> </div> <div> <button data-modal-toggle="defaultModal" type="button" @click="saveEdit">Save</button> </div> </div> </template> <script lang="ts" setup> import { api } from "../lib/api"; import { ref, watch } from "vue"; // 修正props类型:传入的是对象而非字符串 const props = defineProps({ todo: Object, }) const emit = defineEmits(['toggle']); // 复制props的todo到本地响应式变量,作为编辑数据源 const localTodo = ref({...props.todo}); // 监听props变化,确保打开新的编辑内容时同步本地状态 watch(() => props.todo, (newTodo) => { localTodo.value = {...newTodo}; }, {deep: true}) function saveEdit() { try { // 使用本地编辑后的最新值调用API api.updateBlog(localTodo.value.blogId, localTodo.value.post).then(res => { emit('toggle', false); // 保存成功后关闭模态框 }) } catch (e) { console.log('Error while updating post: '+ e) } } </script>
2. 父组件简化(移除不必要逻辑)
<template> <div v-show="isOpened"> <!-- 移除不需要的update:todo事件和updatedText props --> <EditModal @toggle="closeModal" :todo="modalPost" /> </div> </template> <script setup lang="ts"> import Post from "../components/Post.vue"; import { api } from "../lib/api"; import { ref } from "vue"; import { onMounted } from "vue-demi"; import EditModal from "../components/EditModal.vue"; const postArr = ref(''); const message = ref(''); let isOpened = ref(false); let modalPost = ref(''); function closeModal() { isOpened.value = false } function openModal(value: string) { isOpened.value = true modalPost.value = value } // 若保存后需要刷新列表,可在子组件新增emit事件,父组件监听后调用posts()即可 </script>
关键说明
- 修正props类型:之前将
todo定义为String是错误的,实际传入的是对象,需改为Object。 - 本地维护编辑状态:通过
localTodo复制props数据,避免直接修改只读的props,同时保证编辑内容实时更新。 - 去掉冗余emit:子组件独立完成保存,无需向父组件传递更新后的值,仅需emit关闭模态框的事件。
内容的提问来源于stack exchange,提问作者Mike3355
相关产品推荐
相关产品推荐

