Vue.js中子组件动态传递Props问题:页面加载时模态框无法正常显示
问题分析与解决方案
这问题我之前开发Vue项目时也碰到过,核心原因是Modal组件里的popModal只在初始化时读取了一次isShow的props值,之后父组件更新isShow时,不会自动同步到子组件的popModal变量里。
为什么会出现这个情况?
Vue组件的生命周期顺序是这样的:
- 父组件
beforeCreate→created→beforeMount - 子组件
beforeCreate→created→beforeMount→mounted - 父组件
mounted
你在父组件mounted钩子中把showModal设为true时,子组件Modal已经完成了data的初始化(此时isShow还是初始的false,所以popModal被赋值为false)。之后父组件的showModal更新,子组件的isShowprops确实会变化,但popModal是子组件自己的data变量,不会自动跟着props更新,所以Devtools里看到popModal还是false。
几种可行的解决方案
方案1:用watch监听props变化同步popModal
在Modal组件中添加一个监听器,当isShow变化时自动更新popModal,同时关闭Modal时要通知父组件同步状态:
<!-- Modal.vue --> <template> <modal v-if="popModal" v-model="popModal"> <p>xxxxxx</p> <button @click="fn()">Click</button> </modal> </template> <script> export default { props: ['isShow'], data () { return { popModal: this.isShow } }, watch: { // 监听isShow的变化,同步到popModal isShow(newVal) { this.popModal = newVal; } }, methods: { fn() { this.popModal = false; // 通知父组件更新showModal this.$emit('update:isShow', false); } } } </script>
父组件可以用.sync修饰符简化双向绑定:
<!-- Main.vue --> <modal :isShow.sync="showModal"></modal>
方案2:直接使用props,去掉中间的popModal变量
如果不需要在子组件里维护独立的状态,直接用props控制显示,关闭时触发事件通知父组件:
<!-- Modal.vue --> <template> <modal v-if="isShow"> <p>xxxxxx</p> <button @click="handleClose">Click</button> </modal> </template> <script> export default { props: ['isShow'], methods: { handleClose() { this.$emit('update:isShow', false); } } } </script>
父组件同样用.sync绑定:
<modal :isShow.sync="showModal"></modal>
方案3:用computed属性实现双向同步
把popModal改成带getter和setter的计算属性,既自动同步props,又能在修改时通知父组件:
<!-- Modal.vue --> <template> <modal v-if="popModal" v-model="popModal"> <p>xxxxxx</p> <button @click="fn()">Click</button> </modal> </template> <script> export default { props: ['isShow'], computed: { popModal: { get() { // 从props取值 return this.isShow; }, set(newVal) { // 修改时通知父组件 this.$emit('update:isShow', newVal); } } }, methods: { fn() { this.popModal = false; } } } </script>
这种方式最简洁,推荐使用,因为计算属性会自动响应props的变化,同时支持修改时的双向绑定。
额外优化:自定义v-model
如果你想让父组件直接用v-model而不是.sync,可以在Modal组件里配置model选项:
// Modal.vue export default { model: { prop: 'isShow', // 绑定的props名称 event: 'update:isShow' // 触发的事件名称 }, props: ['isShow'], // ...其他代码 }
这样父组件就能像使用原生表单组件一样写:
<modal v-model="showModal"></modal>
内容的提问来源于stack exchange,提问作者OSW
相关产品推荐
相关产品推荐

