使用$mount和extend扩展vue
上一篇我已经对popup组件进行了封装,在要使用的地方进行import即可。但如果使用过于频繁你又不想注册为全局组件,这里就不得不利用vue的$mount和extend方法了。
$mount大家应该都很熟悉了,在vue项目的main.js中都有使用:
new Vue({
render: h => h(App),
}).$mount('#app')
//或者
const app = new Vue({
render: h => h(App),
})
app.$mount('#app');
// 又或者
new Vue({
el: '#app',
render: h => h(App)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
官方文档说的很详细,new Vue时指定el会自定调用$mount,如果没有指定可以在后面手动调用$mount方法进行挂载
extend的作用是为vue组件构建一个子类,它一般搭配$mount方法使用。先创建组件实例在通过$mount动态挂载元素。
将上一篇的popup代码修改如下:
<template>
<div class="popup" :class="showPop ? 'show' : 'hide'">
<div class="mask">
<div class="body">
<div class="title">{{title}}</div>
<div class="content">{{content}}</div>
<div class="btn">
<div class="button" @click="cancelClick">{{cancelText}}</div>
<div class="button" @click="confirmClick">{{confirmText}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
title: '',
content: '',
cancelText: '',
confirmText: '',
confirm: null,
cancel: null,
// 没有隐藏状态,只存在显示和移除状态
showPop: true
}
},
methods: {
confirmClick() {
if(typeof this.confirm == 'function') {
this.confirm('click:comfirm');
this.destorySelf();
}
},
cancelClick() {
if(typeof this.cancel == 'function') {
this.cancel('click:cancel');
this.destorySelf();
}
},
// 移除
destorySelf() {
this.showPop = false;
// 延迟以播放动画
setTimeout(() => {
// 销毁实例 移除事件、指令,删除子实例,但dom依然存在
this.$destroy(true);
// 从dom节点删除
this.$el && this.$el.parentNode.removeChild(this.$el)
}, 200);
}
},
mounted() {
}
}
</script>
<style scoped>
.popup,.mask {
position: fixed;
z-index: 10000;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.popup .mask {
position: fixed;
z-index: 10001;
background: rgba(1,1,1,0);
}
.popup .mask .body {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
z-index: 10002;
width: 60%;
min-height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #FFFFFF;
border-radius: 10px;
text-align: center;
}
.popup .mask .body .content{
padding: 10px 25px 20px;
text-align: center;
font-size: 18px;
color: #333333;
}
.popup .mask .body .title {
padding: 5px 25px;
text-align: center;
font-size: 22px;
color: #333333;
}
.popup .mask .body .btn {
display: flex;
flex-direction: row;
align-items: center;
height: 50px;
border-top: 1px solid #005599;
}
.popup .mask .body .btn .button {
flex: 1;
line-height: 2;
text-align: center;
box-sizing: border-box;
color: #005599;
}
.popup .mask .body .btn .button + .button {
border-left: 1px solid #005599;
}
.popup.show .mask {
animation: maskShow .2s linear forwards;
}
.popup.hide .mask {
animation: maskHide .2s linear forwards;
}
.popup.show .mask .body {
animation: bodyShow .2s linear forwards;
}
.popup.hide .mask .body {
animation: bodyHide .2s linear forwards;
}
/* mask入场动画 */
@keyframes maskShow{
from{
background-color: rgba(1,1,1,0);
}
to{
background-color: rgba(1,1,1,.4);
}
}
/* body入场动画 */
@keyframes bodyShow{
from{
opacity: 0;
}
to{
opacity: 1;
}
}
/* mask退场动画 */
@keyframes maskHide{
from{
background-color: rgba(1,1,1,.4);
}
to{
background-color: rgba(1,1,1,0);
}
}
/* body退场动画 */
@keyframes bodyHide{
from{
opacity: 1;
}
to{
opacity: 0;
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
添加控制modal生成文件
- 使用extend生成新的modal实例
- new modal时传入data参数,它会自动给modal组件data赋值。注意这里data可以不是函数
- 使用$mount挂载,因为没有提供挂载元素需要手动使用appendChild添加到真实dom
- 使用vue插件使用方式
install导出用于Vue.use使用
// modal.js
import Vue from 'vue'
import modal from './modal.vue'
const modalSub = Vue.extend(modal)
export function createModal(options) {
let m = new modalSub({
data: {
title: options && options.title || '',
content: options && options.content || '',
cancelText: options && options.cancelText || '取消' ,
confirmText: options && options.confirmText || '确定',
confirm: options && options.confirm || null,
cancel: options && options.cancel || null
}
});
let vm = m.$mount();
document.querySelector('#app').appendChild(vm.$el);
return vm;
}
export default {
install: (Vue) => {
Vue.prototype.$modal = createModal;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
在main.js中添加以下代码,即可在工程中使用
// main.js
import modal from './modal/modal.js'
Vue.use(modal);
1
2
3
2
3
具体使用方式如下:
// 打开模态框
this.$modal({
title: 'title',
content: '内容内容内容内容内容内容内容内容内容内容内容内容内容',
cancelText: '取消测试',
confirmText: '确定测试',
confirm: (e) => {
console.log(e);
},
cancel: (e) => {
console.log(e);
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
上次更新: 2025/09/05, 8:09:00