Vue父组件传v-model控制子组件v-dialog出现prop修改报错如何解决
问题原因
- 报错原因:子组件直接对props传入的
dialog使用v-model双向绑定,v-dialog关闭时会直接修改这个props值,违反了Vue单向数据流规则(子组件不能直接修改父组件传入的props),因此触发控制台警告。 - 多弹窗同时打开原因:你给所有循环生成的
DialogsOverview组件绑定了同一个父级dialog布尔变量,只要这个变量变为true,所有弹窗都会同时触发显示。
修复方案
方案1:保留多弹窗结构修复(最小改动)
父组件修改
- 将全局
dialog布尔值改为存储当前激活的弹窗对应条目ID,初始值为null - 点击按钮时传入当前条目的ID赋值
- 监听子组件抛出的关闭事件,重置激活ID为
null - 给每个子组件的
dialog属性赋值为「当前条目ID等于激活ID」的判断结果
修改后父组件代码:
<template> <div> <div class="container"> <v-card v-for="el of listTv" :key="el.id" class="card" :style="{ backgroundImage: `url('https://image.tmdb.org/t/p/w500/${el.backdrop_path}')`, backgroundSize: 'auto', backgroundPosition: 'center', }" > <v-card-title class="textTitle">{{ el.name }}</v-card-title> <h5 class="genres"> {{ el.genres[0] === undefined ? "Nessun genere" : el.genres[0].name }} </h5> <v-btn color="primary" class="btn" @click="activeDialogId = el.id" >Trama...</v-btn > </v-card> </div> <DialogsOverview v-for="element in listTv" :key="element.id" :overView="element.overview || 'Nessuna descrizione'" :title="element.name" :dialog="activeDialogId === element.id" @close="activeDialogId = null" /> </div> </template> <script> import DialogsOverview from "./DialogsOverview.vue"; export default { components: { DialogsOverview }, props: ["listTv"], data() { return { activeDialogId: null, }; }, }; </script> <style> @import url("./style/CardsMovie.css"); </style>
子组件修改
将v-model拆分为单向绑定+事件抛出,不直接修改props:
<template> <div> <v-dialog :value="dialog" @input="$emit('close', $event)"> <v-card> <v-card-title>{{ title }}</v-card-title> <v-card-text>{{ overView }}</v-card-text> </v-card> </v-dialog> </div> </template> <script> export default { props: { dialog: Boolean, overView: String, title: String, }, }; </script>
方案2:优化为单弹窗(更推荐,性能更好)
不需要循环生成N个弹窗,只保留1个弹窗实例,点击对应卡片时传入对应内容即可:
父组件修改后代码
<template> <div> <div class="container"> <v-card v-for="el of listTv" :key="el.id" class="card" :style="{ backgroundImage: `url('https://image.tmdb.org/t/p/w500/${el.backdrop_path}')`, backgroundSize: 'auto', backgroundPosition: 'center', }" > <v-card-title class="textTitle">{{ el.name }}</v-card-title> <h5 class="genres"> {{ el.genres[0] === undefined ? "Nessun genere" : el.genres[0].name }} </h5> <v-btn color="primary" class="btn" @click="openDialog(el)" >Trama...</v-btn > </v-card> </div> <!-- 只保留一个弹窗实例 --> <DialogsOverview :dialog="dialogVisible" :overView="currentItem.overview || 'Nessuna descrizione'" :title="currentItem.name" @close="dialogVisible = false" /> </div> </template> <script> import DialogsOverview from "./DialogsOverview.vue"; export default { components: { DialogsOverview }, props: ["listTv"], data() { return { dialogVisible: false, currentItem: {}, // 存储当前选中的条目 }; }, methods: { openDialog(item) { this.currentItem = item this.dialogVisible = true } } }; </script> <style> @import url("./style/CardsMovie.css"); </style>
子组件代码和方案1的子组件代码完全一致即可。
内容的提问来源于stack exchange,提问作者Stefano
相关产品推荐
相关产品推荐

