vue创建一个body作为父元素的弹窗

发布: 2018-07-16 23:42:31标签: vue

分别借鉴elementui的dialog和mint-ui的toast组件

最新版弹窗

01<template>
02 <div v-if='visible' class='my-model center-flex'>
03 <div @click='close' ref='model' class='bg'></div>
04 <div class='wrapper'>
05 <slot></slot>
06 </div>
07 </div>
08</template>
09
10<script>
11 export default {
12 props: {
13 visible: {
14 type: Boolean,
15 default: true
16 },
17 appendToBody: {
18 type: Boolean,
19 default: true
20 }
21 },
22 data() {
23 return {
24 }
25 },
26 watch: {
27 visible() {
28 this.disabledScroll()
29 }
30 },
31 methods: {
32 close() {
33 this.$emit('close')
34 },
35 initModel() {
36 if (this.appendToBody) {
37 document.body.appendChild(this.$el)
38 }
39 },
40 disabledScroll() {
41 if (this.visible) {
42 this.$nextTick(() => {
43 this.$refs.model.ontouchmove = (e) => {
44 e.preventDefault()
45 }
46 })
47 }
48 }
49 },
50 mounted() {
51 this.initModel()
52 this.disabledScroll()
53 },
54 beforeDestroy() {
55 if (this.appendToBody && this.$el && this.$el.parentNode) {
56 this.$el.parentNode.removeChild(this.$el);
57 }
58 }
59 }
60</script>
61
62<style lang='scss' scoped>
63 .my-model {
64 position: fixed;
65 left: 0;
66 top: 0;
67 width: 100%;
68 height: 100%;
69 }
70
71 .bg {
72 display: block;
73 width: 100%;
74 height: 100%;
75 background: rgba(0, 0, 0, 0.3);
76 position: absolute;
77 left: 0;
78 top: 0;
79 }
80
81 .wrapper {
82 position: relative;
83 z-index: 1;
84 background: white;
85 }
86</style>
87
复制代码

老版本弹窗

model.js

01import Vue from 'vue'
02
03const Model = Vue.extend(require('./MyModel').default)
04let instance
05
06export default {
07 show(component) {
08 if (!instance) {
09 // 第一次创建
10 instance = new Model({
11 el: document.createElement('div')
12 })
13 document.body.appendChild(instance.$el)
14 instance.componentName = component
15 } else {
16 // 已经创建
17 if (instance.visible) return
18 instance.componentName = component
19 instance.visible = true
20 }
21 },
22
23 close() {
24 if (instance) {
25 instance.visible = false
26 }
27 }
28}
29
复制代码

组件

01<template>
02 <div v-if='visible' class='my-model center-flex'>
03 <div @click='close' ref='model' class='bg'></div>
04 <div class='wrapper'>
05 <component v-if='componentName' :is='componentName'></component>
06 </div>
07 </div>
08</template>
09
10<script>
11 export default {
12 data() {
13 return {
14 visible: true,
15 componentName: ''
16 }
17 },
18 methods: {
19 close() {
20 this.visible = false
21 }
22 },
23 mounted() {
24 this.$nextTick(() => {
25 this.$refs.model.ontouchmove = (e) => {
26 e.preventDefault()
27 }
28 })
29 }
30 }
31</script>
32
33<style lang='scss' scoped>
34 .my-model {
35 position: fixed;
36 left: 0;
37 top: 0;
38 width: 100%;
39 height: 100%;
40 }
41
42 .bg {
43 display: block;
44 width: 100%;
45 height: 100%;
46 background: rgba(0, 0, 0, 0.3);
47 position: absolute;
48 left: 0;
49 top: 0;
50 }
51
52 .wrapper {
53 position: relative;
54 z-index: 1;
55 background: white;
56 }
57</style>
58
复制代码