Vue.js模态框slotContent传值为null问题求助
模态窗口slotContent无法传递至Vue.js模板
中心类型模态框的所有参数均可正常传递,但向slotContent传递对象或纯文本时,在Modal.vue模板中该值始终为null。调试ModalPlugin的show()方法时能确认内容已传入,但在以下代码片段中slotContent显示为null:
<template v-else-if="type === 'bottom'"> <component v-if="slotContent" :is="slotContent" /> </template>
相关代码
ModalPlugin.js
import { reactive } from "vue"; import Modal from "@/views/components/Modal.vue"; export default { install(app) { const state = reactive({ visible: false, type: "center", title: "", message: "", icon: "", hasAction: false, actionText: "", callback: null, slotContent: null, }); app.component("Modal", Modal); app.config.globalProperties.$modal = { show(options) { Object.assign(state, options, { visible: true }); }, hide() { Object.assign(state, { visible: false, slotContent: null, callback: null, }); }, }; app.provide("modalState", state); }, };
Modal.vue
<template> <div v-if="visible" :class="['modal', type]" @click.self="close" > <div class="modal__content"> <button class="modal__close" @click="close"> <img src="~@/assets/images/modal/close.png" alt=""> </button> <template v-if="type === 'center'"> <div class="modal__image"> <img :src="icon" alt="" /> </div> <p class="title">{{ title }}</p> <p class="text" v-html="message"></p> <button v-if="hasAction" class="btn btn__primary" @click="action"> {{ actionText }} </button> </template> <template v-else-if="type === 'bottom'"> <component v-if="slotContent" :is="slotContent" /> </template> </div> </div> </template> <script> import '../../styles/components/Modal.scss'; export default { name: "Modal", props: { visible: { type: Boolean, default: false }, type: { type: String, default: "center" }, title: { type: String, default: "" }, message: { type: String, default: "" }, icon: { type: String, default: "" }, hasAction: { type: Boolean, default: false }, actionText: { type: String, default: "OK" }, slotContent: { type: [String, Object, Function], default: null }, }, emits: ["close", "action"], methods: { close() { this.$emit("close"); }, action() { this.$emit("action"); }, } }; </script>
ShopView.vue
<template> <div class="shop"> <div class="shop__list"> <button class="shop__list__btn glitter" @click="openModal('boost', 'Boost')"> <img src="~@/assets/images/shop/boost.png" alt=""> <p>Прокачаться</p> </button> <button class="shop__list__btn glitter" @click="openModal('exchange', Exchange)"> <img src="~@/assets/images/shop/exchange.png" alt=""> <p>Обменник</p> </button> <button class="shop__list__btn glitter" @click="openModal('buyDiamonds', BuyDiamond)"> <img src="~@/assets/images/shop/diamond.png" alt=""> <p>Купить алмазы</p> </button> <button class="shop__list__btn glitter" @click="openModal('withdraw', Withdrawal)"> <img src="~@/assets/images/shop/withdraw.png" alt=""> <p>Вывести деньги</p> </button> </div> </div> </template> <script> import '../styles/components/Shop.scss'; import Boost from './components/shop/Boost.vue'; import BuyDiamond from './components/shop/BuyDiamond.vue'; import Exchange from './components/shop/Exchange.vue'; import Withdrawal from './components/shop/Withdrawal.vue'; export default { name: "ShopView", components: { Boost, BuyDiamond, Exchange, Withdrawal }, methods: { openModal(type, slotContent) { this.$modal.show({ type: 'bottom', slotContent, }); } }, }; </script>
问题根源与修复方案
问题核心
Modal组件通过props接收参数,但插件中仅将状态存入reactive对象,未将状态与Modal组件的props绑定,导致slotContent等参数无法同步到组件内部。中心类型能工作是因为可能手动传递了对应props,但slotContent被遗漏。
修复步骤
修改Modal.vue,通过inject接收全局状态
移除props,直接注入插件提供的modalState,利用响应式特性同步状态:<template> <div v-if="modalState.visible" :class="['modal', modalState.type]" @click.self="close" > <div class="modal__content"> <button class="modal__close" @click="close"> <img src="~@/assets/images/modal/close.png" alt=""> </button> <template v-if="modalState.type === 'center'"> <div class="modal__image"> <img :src="modalState.icon" alt="" /> </div> <p class="title">{{ modalState.title }}</p> <p class="text" v-html="modalState.message"></p> <button v-if="modalState.hasAction" class="btn btn__primary" @click="action"> {{ modalState.actionText }} </button> </template> <template v-else-if="modalState.type === 'bottom'"> <component v-if="modalState.slotContent" :is="modalState.slotContent" /> </template> </div> </div> </template> <script> import '../../styles/components/Modal.scss'; import { inject } from 'vue'; export default { name: "Modal", emits: ["close", "action"], setup() { const modalState = inject('modalState'); return { modalState }; }, methods: { close() { this.$modal.hide(); }, action() { this.modalState.callback?.(); this.$modal.hide(); }, } }; </script>确认全局挂载Modal的方式
在入口文件或App.vue中直接挂载Modal组件,无需传递props:<template> <div id="app"> <!-- 其他业务组件 --> <Modal /> </div> </template>ShopView.vue逻辑保持不变
原有的openModal调用逻辑无需修改,$modal.show()会自动将参数合并到全局响应式状态中,Modal组件会同步更新。
内容的提问来源于stack exchange,提问作者Андрей Дмитрук
相关产品推荐
相关产品推荐

