---
# System prepended metadata

title: Vue.js 2 封裝 Modal / Loading Plugin 方法
tags: [Vue.js, Vue Plugins]

---

###### <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")