###### <p style="text-align: right"> 建立日期:2021-01-13 / 更新日期:2021-02-14</p>
# Vue.js 2 封裝 Modal / Loading Plugin 方法
###### tags: `Vue.js` `Vue Plugins`
## 資料夾架構
* 在 **plugins** 資料夾內新增 **modal** 資料夾,裡面放置 **index.js**
* **Modal.vue** 可以放在 **modal** 資料夾內,或是放在 **components** 資料夾,`import` 時路徑寫對即可
## index.js
:::spoiler 點擊顯示完整內容
```javascript=
import modalComponent from './Modal.vue';
const modal = {
install(Vue) {
// 1. 創建子類
const ModalConstructor = Vue.extend(modalComponent);
// 2. 創建子類的實例並掛載到 div 上
const modalInstance = new ModalConstructor({
el: document.createElement('div'),
});
// 2. 等同上面,另一種寫法
// const modalInstance = new ModalConstructor().$mount(document.createElement('div'));
// 3. 掛載實例後,元素可用 $el 訪問,將元素新增至 document.body
document.body.appendChild(modalInstance.$el);
// 4. 定義 Global 可用的 methods
const modalMethods = {
open(title, body, btnText) {
modalInstance.open(title, body, btnText);
},
hide() {
modalInstance.hide();
},
};
// 5. 註冊到 Global
/* eslint-disable no-param-reassign */
Vue.prototype.$modal = modalMethods;
/* eslint-disable no-param-reassign */
},
};
export default modal;
```
:::
## Modal.vue
:::spoiler 點擊顯示完整內容
```javascript=
<template lang="pug">
.semi-transparent(:class="{'hide': !display}")
.modal
.modal__title {{ title }}
.modal__body(:class="{ imgTick: !msg }") {{ msg }}
.modal__footer
button(@click="hide()") {{ btnText }}
</template>
<script>
export default {
name: 'Modal',
data() {
return {
display: false,
title: '',
msg: '',
btnText: '',
};
},
methods: {
open({ title, msg, btnText }) {
this.title = title;
this.msg = msg;
this.btnText = btnText;
this.display = true;
},
hide() {
this.display = false;
this.title = '';
this.msg = '';
this.btnText = '';
},
},
};
</script>
<style lang="sass" scoped>
$primary-color: #ffffff
@mixin flex($jc: flex-start, $ai: flex-start)
display: flex
justify-content: $jc
align-items: $ai
@mixin zebra-three-slashes
$bg: rgba(255, 255, 255, 0.3)
$bgW: 8
$line-color: #575757
$lineW: 1.5
width: 45px
height: 9px
background-image: repeating-linear-gradient(45deg, $bg, $bg #{$bgW}px, $lineColor #{$bgW}px, $bg #{$bgW + $lineW}px, $bg #{$bgW + $lineW + 1}px)
.semi-transparent
width: 100vw
height: 100vh
position: fixed
top: 0
left: 0
background: rgba(#000000, 0.5)
@include flex(center, center)
.modal
width: 423px
padding: 32px 42px
background: $primary-color
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.5)
*
font-weight: 500
.modal__title
font-size: 24px
line-height: 36px
letter-spacing: 2.5px
margin-bottom: 31px
position: relative
&::before
content: ''
position: absolute
bottom: -15px
left: 0
@include zebra-three-slashes
.modal__body
margin-bottom: 30px
.imgTick
background-image: top center url('~@/assets/images/modal/yourImg.svg') no-repeat
.modal__footer
@include flex(flex-end)
button
padding: 8px 24px
background: #484848
color: $primary-color
</style>
```
:::
## main.js
:::spoiler 點擊顯示完整內容
```javascript=
import pluginModal from './plugins/modal';
Vue.use(pluginModal);
```
:::
## 參考資料
* [我们一起写一个Vue的Loading插件吧](https://juejin.cn/post/6844903876580098056#heading-5 "title")