笔记-使用AntDesignVue的Modal组件

本文介绍了一个在Vue.js中使用的可定制弹窗组件(a-modal),展示了如何通过父子组件间的props和事件传递控制其显示、隐藏及输入框交互,以及如何响应关闭和确认操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击出弹窗a-modal
// ChildCpn
<template>
  <div class="index">
    <a-modal
      // 标题设置
      title="规则设置"
      // 显示隐藏,属性由父组件传进来控制
      :visible="visible"
      // 控制位置和圆角
      :dialog-style="{
        top: '.86rem',
        borderRadius: '.06rem'
      }"
      // 控制宽度
      width="2.23rem"
      // 点击遮罩或者是关闭按钮
      @cancel="cancelClick"
      // 点击确认按钮
      @ok="sureClick"
    >
      <a-row class="pcts">
        <p>频次天数</p>
        <a-input placeholder="请输入" />
      </a-row>
      <a-row>
        <p>出入频次</p>
        <a-input placeholder="请输入" />
      </a-row>
    </a-modal>
  </div>
</template>

<script>
export default {
	// 父组件传入控制显示隐藏
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  methods: {
  	// 点击关闭或者是遮罩发射关闭信号给父组件,控制关闭
    cancelClick () {
      this.$emit('modalClose')
    },
    // 点击确认执行成功事件
    sureClick () {
      this.$emit('modalClose')
    }
  }
}
</script>

<style lang="less" scoped>
  .pcts {
    margin-bottom: .13rem;
  }
</style>



// ParentCpn
// 导入
import ChildCpn from './ChildCpn'

// 使用
<modal-box
	:visible="show"
	@modalClose="modalClose"
/>

data () {
	return {
		show: false
	}
},
components: {
	ChildCpn
},
methods: {
	// 点击按钮改为true,弹窗显示
	modalClick () {
		this.show = true
	},
	// 接收关闭事件,将show改为false
	modalClose () {
		this.show = false
	}
}
<think>我们正在使用portal-vueant-design-vue来实现Modal的交互。PortalVue允许我们将内容渲染到DOM树中的任意位置,这对于Modal、Tooltip等需要脱离当前组件层级的组件非常有用。 步骤: 1. 安装必要的库:ant-design-vue 和 portal-vue 2. 在Vue项目中设置portal-vue插件 3. 使用ant-design-vueModal组件,并结合portal-vue的<portal>或<portal-target>来将Modal内容传送到指定的位置(比如body的末尾) 注意:ant-design-vueModal组件本身已经使用了类似的Portal技术(通过Vue的createAPI),但如果我们想要更精细地控制或者需要自定义Modal的传送行为,我们可以结合portal-vue来实现。 但是,如果ant-design-vueModal已经内置了Portal功能,那么我们可能不需要再使用portal-vue来包裹它。不过,这里我们假设需要自定义传送目标,或者我们想用portal-vue来传送其他内容。 下面是一个示例,展示如何使用portal-vueant-design-vueModal: 首先,我们安装portal-vueant-design-vue。 然后,在main.js中设置: ```javascript import Vue from 'vue'; import PortalVue from 'portal-vue'; import Antd from 'ant-design-vue'; import 'ant-design-vue/dist/antd.css'; Vue.use(PortalVue); Vue.use(Antd); ``` 接下来,我们创建一个自定义的Modal使用portal-vueModal的内容传送到body的末尾。 但是,ant-design-vueModal组件有一个`getContainer`属性,可以指定Modal挂载的容器。所以我们可以这样使用: ```vue <template> <div> <a-button type="primary" @click="showModal">打开Modal</a-button> <!-- 使用ant-designModal --> <a-modal title="Basic Modal" :visible="visible" @ok="handleOk" @cancel="handleCancel" :getContainer="getContainer" > <p>Some contents...</p> </a-modal> <!-- 使用portal-target作为传送目标 --> <portal-target name="modal-destination"></portal-target> </div> </template> <script> export default { data() { return { visible: false, }; }, methods: { showModal() { this.visible = true; }, handleOk() { this.visible = false; }, handleCancel() { this.visible = false; }, // 指定Modal挂载到portal-target的位置 getContainer() { // 注意:这里返回的是portal-target的DOM元素 // 但是portal-target渲染出来的是一个div,我们通过name找到它 // 但是注意,portal-target可能还没有渲染,所以我们可以先创建一个容器,然后让portal-target渲染到那个容器 // 实际上,ant-design-vue默认会挂载到body上,我们这里为了演示使用portal-target,可以这样: // 但是注意:portal-target本身并不是一个容器,而是一个目标位置。我们通常将portal的内容传送到这个目标位置。 // 所以,我们不应该用getContainer返回portal-target,因为getContainer需要返回一个DOM节点。 // 其实,我们也可以使用portal-vue的<portal>来传送Modal的内容,但是ant-design-vueModal已经封装好了,所以我们不改变其内容,而是改变其容器。 // 另一种思路:我们不用ant-design-vueModal,而是自己用portal-vue实现一个类似Modal组件,这样我们可以完全控制传送。 // 考虑到简单性,我们这里直接使用ant-design-vueModal,并利用其getContainer属性将其挂载到我们指定的容器(比如一个在body下的div)。 // 所以,我们可以在mounted时创建一个容器,并挂载到body上,然后getContainer返回这个容器。 // 但是注意,ant-design-vueModal已经做了类似的事情,所以我们其实不需要portal-vue也可以。 // 因此,如果我们只是想将Modal挂载到body的某个位置,可以直接使用ant-design-vueModal,它默认就是挂载到body上的。 // 所以,我们这里不需要portal-vue?那么为什么题目要求使用portal-vue呢? // 重新理解需求:使用portal-vue实现ant-design组件库的modal框交互。可能是指我们自己用ant-design组件和portal-vue来组合实现一个Modal,而不是直接使用a-modal。 // 因此,我们改变思路:自己封装一个Modal使用ant-design-vue的样式和组件,但内容传送用portal-vue。 // 我们使用portal-vue的<portal>将内容传送到<portal-target>,而<portal-target>我们放在body的末尾。 // 所以,我们可以在App.vue的根元素外设置一个portal-target,然后在Modal组件使用portal将内容传送过去。 // 下面我们改变写法,自己封装一个Modal。 }, }, }; </script> ``` 由于直接使用ant-design-vueModal可能无法体现portal-vue的作用,我们改为自己封装一个Modal组件使用ant-design-vue的样式和组件,但内容传送使用portal-vue。 具体步骤: 1. 在App.vue中,我们在根元素之外放置一个portal-target,这样它就在body的直接子元素了。 2. 创建一个自定义的Modal组件,内部使用ant-design-vueModal样式和交互,但内容通过portal传送到App.vue中的portal-target。 但是,ant-design-vueModal不仅仅是一个内容框,还包括遮罩层等。我们可以参考ant-design-vueModal自己实现一个类似的,但使用portal-vue来传送。 这里我们简化实现,只传送内容,遮罩层我们也可以传送,或者使用固定定位覆盖整个视口。 自定义Modal组件(MyModal.vue)示例: ```vue <template> <portal to="modal-destination"> <!-- 遮罩层 --> <div v-if="visible" class="ant-modal-mask" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:1000;"></div> <!-- 模态框 --> <div v-if="visible" class="ant-modal-wrap" style="position:fixed;top:0;left:0;right:0;bottom:0;z-index:1000;overflow:auto;outline:0;"> <div class="ant-modal" style="position:relative;top:100px;width:400px;margin:0 auto;"> <div class="ant-modal-content"> <button class="ant-modal-close" @click="handleCancel"> <span class="ant-modal-close-x"></span> </button> <div class="ant-modal-header"> <div class="ant-modal-title">{{ title }}</div> </div> <div class="ant-modal-body"> <slot></slot> </div> <div class="ant-modal-footer"> <button @click="handleCancel">取消</button> <button @click="handleOk">确定</button> </div> </div> </div> </div> </portal> </template> <script> export default { props: { visible: Boolean, title: String }, methods: { handleOk() { this.$emit('ok'); }, handleCancel() { this.$emit('cancel'); } } }; </script> ``` 然后在App.vue中: ```vue <template> <div id="app"> <!-- 其他内容 --> <button @click="showModal">打开Modal</button> <MyModal :visible="modalVisible" title="自定义Modal" @ok="handleOk" @cancel="handleCancel"> <p>这是自定义Modal的内容</p> </MyModal> <!-- 传送目标 --> <portal-target name="modal-destination"></portal-target> </div> </template> <script> import MyModal from './components/MyModal.vue' export default { components: { MyModal }, data() { return { modalVisible: false } }, methods: { showModal() { this.modalVisible = true }, handleOk() { this.modalVisible = false // 处理确定逻辑 }, handleCancel() { this.modalVisible = false } } } </script> ``` 这样,当MyModal组件内的portal激活时,内容会被传送到<portal-target name="modal-destination">,而这个目标在App.vue中,由于App.vue是挂载在body内的,所以内容就在body的直接子元素了。 注意:我们使用ant-design-vue的样式类名,所以需要确保引入了ant-design-vue的样式。 但是,这种方式需要我们自己实现Modal的样式和交互逻辑(比如拖拽、动画等),而ant-design-vueModal组件已经提供了这些。所以,我们也可以考虑另一种方式:使用ant-design-vueModal,但是将其内容通过portal-vue传送到我们指定的位置。不过,ant-design-vueModal组件内部已经使用了它自己的Portal机制(通过Vue.createAPI),所以我们很难直接将其内容用portal-vue再传送一次。 因此,如果我们需要完全控制传送的位置,并且希望与ant-design-vue的样式和组件保持一致,我们可以选择自己封装一个简单的Modal,如上所示。 但是,如果我们只是希望Modal能够渲染到body上,避免被父组件的样式影响,那么ant-design-vueModal已经默认这样做了。所以,使用portal-vue可能不是必须的。 总结:根据需求,如果我们必须使用portal-vue,那么我们可以自己封装一个Modal组件,利用portal-vue将内容传送到body下的指定位置。如果不需要,直接使用ant-design-vueModal即可。 相关问题: 1. portal-vueVue3中如何使用? 2. ant-design-vueModal组件有哪些常用的API? 3. 如何自己实现一个Modal组件(包括动画、可访问性等)?</think>### 使用 PortalVue 实现 Ant Design Modal 交互 #### 核心思路 PortalVue 允许将组件内容渲染到 DOM 树中的任意位置,结合 Ant Design VueModal 组件使用时,主要解决两个问题: 1. **内容传送**:将 Modal 内容渲染到 `<body>` 层级,避免父组件样式影响 2. **状态管理**:保持 Modal 状态与 Vue 组件上下文关联 #### 实现步骤 1. **安装依赖** ```bash npm install portal-vue ant-design-vue ``` 2. **全局注册 PortalVue(main.js)** ```javascript import PortalVue from 'portal-vue' import Antd from 'ant-design-vue' Vue.use(PortalVue) Vue.use(Antd) ``` 3. **创建可复用的 Modal 组件(PortalModal.vue)** ```vue <template> <!-- 传送门目标位置 --> <portal to="modal-root"> <!-- Ant Design Modal 组件 --> <a-modal :visible="visible" :title="title" @ok="handleOk" @cancel="handleCancel" > <slot></slot> </a-modal> </portal> </template> <script> export default { props: { visible: Boolean, title: String }, methods: { handleOk() { this.$emit('ok') }, handleCancel() { this.$emit('cancel') } } } </script> ``` 4. **在根组件设置传送目标(App.vue)** ```vue <template> <div id="app"> <!-- 其他内容 --> <!-- 专门用于渲染 Modal 的 DOM 节点 --> <portal-target name="modal-root" class="modal-container" /> </div> </template> <style> /* 确保 Modal 在 body 层级 */ .modal-container { position: relative; z-index: 1000; } </style> ``` 5. **在业务组件使用** ```vue <template> <div> <a-button @click="showModal">打开弹窗</a-button> <PortalModal :visible="modalVisible" title="示例弹窗" @ok="handleConfirm" @cancel="hideModal" > <p>这是通过 PortalVue 渲染的内容</p> <a-input v-model="inputValue" placeholder="输入测试" /> </PortalModal> </div> </template> <script> import PortalModal from './PortalModal.vue' export default { components: { PortalModal }, data() { return { modalVisible: false, inputValue: '' } }, methods: { showModal() { this.modalVisible = true }, hideModal() { this.modalVisible = false }, handleConfirm() { console.log('输入值:', this.inputValue) this.hideModal() } } } </script> ``` #### 关键优势 1. **层级控制**:解决 Modal 被父容器 `overflow:hidden` 截断的问题 2. **状态保持**:Modal 内容仍属于 Vue 组件树,可正常访问父组件状态 3. **性能优化**:避免重复创建/销毁 DOM 节点,通过 `v-if` 控制渲染 4. **样式隔离**:通过传送门机制实现 CSS 作用域隔离 #### 注意事项 1. **动画处理**:Ant Design Modal 自带动画,需确保传送目标节点在动画期间保持存在 2. **多弹窗管理**:多个 Modal 共用同一传送目标时,需用 `key` 区分 3. **SSR 兼容**:PortalVue 自动处理服务端渲染场景[^1] 4. **内存泄漏**:组件销毁前确保关闭 Modal,避免事件监听残留 > 通过此方案可实现 Ant Design Modal 与 PortalVue 的无缝集成,既保留了 Ant Design 的丰富功能,又利用 Portal 机制解决了渲染层级问题。实际项目中可根据需要扩展 Modal 的 props 和插槽功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你六我里六六

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值