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