vue创建一个body作为父元素的弹窗 发表于 2018-07-16 | 更新于 2023-01-11 分别借鉴elementui的dialog和mint-ui的toast组件 最新版弹窗1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586<template> <div v-if='visible' class='my-model center-flex'> <div @click='close' ref='model' class='bg'></div> <div class='wrapper'> <slot></slot> </div> </div></template><script> export default { props: { visible: { type: Boolean, default: true }, appendToBody: { type: Boolean, default: true } }, data() { return { } }, watch: { visible() { this.disabledScroll() } }, methods: { close() { this.$emit('close') }, initModel() { if (this.appendToBody) { document.body.appendChild(this.$el) } }, disabledScroll() { if (this.visible) { this.$nextTick(() => { this.$refs.model.ontouchmove = (e) => { e.preventDefault() } }) } } }, mounted() { this.initModel() this.disabledScroll() }, beforeDestroy() { if (this.appendToBody && this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el); } } }</script><style lang='scss' scoped> .my-model { position: fixed; left: 0; top: 0; width: 100%; height: 100%; } .bg { display: block; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.3); position: absolute; left: 0; top: 0; } .wrapper { position: relative; z-index: 1; background: white; }</style> 老版本弹窗model.js 12345678910111213141516171819202122232425262728import Vue from 'vue'const Model = Vue.extend(require('./MyModel').default)let instanceexport default { show(component) { if (!instance) { // 第一次创建 instance = new Model({ el: document.createElement('div') }) document.body.appendChild(instance.$el) instance.componentName = component } else { // 已经创建 if (instance.visible) return instance.componentName = component instance.visible = true } }, close() { if (instance) { instance.visible = false } }} 组件 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657<template> <div v-if='visible' class='my-model center-flex'> <div @click='close' ref='model' class='bg'></div> <div class='wrapper'> <component v-if='componentName' :is='componentName'></component> </div> </div></template><script> export default { data() { return { visible: true, componentName: '' } }, methods: { close() { this.visible = false } }, mounted() { this.$nextTick(() => { this.$refs.model.ontouchmove = (e) => { e.preventDefault() } }) } }</script><style lang='scss' scoped> .my-model { position: fixed; left: 0; top: 0; width: 100%; height: 100%; } .bg { display: block; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.3); position: absolute; left: 0; top: 0; } .wrapper { position: relative; z-index: 1; background: white; }</style>