我們在使用vue開發的過程中,經常會遇到這兩個問題:
- 我要使用loading(加載動畫) toast(浮層提示) dialog(彈框提示)之類的全局性元件,但是用全局元件注冊的話非常麻煩,還要在template标簽中書寫元件html代碼然後參數通過在data選項中注冊變量來控制元件的顯示/隐藏/提示語,顯得異常麻煩~
- 我要使用某些全局函數例如(axios)來進行某些操作,如果每次使用都需要import或者require的話,是一件不太優雅的事情
是以我們就想到在vue的全局執行個體Vue或者指向這個執行個體的指針this的原型上添加某一方法來達到随用随取的效果。
本文以loading為例,講下如何編寫一個Vue插件。
首先我們編寫一個普通的loading元件,作為插件的模闆:
// my-project/src/plugin/loading/loading.vue
<template>
<transition :name="animateName">
<div class="loadings" v-show="isShow">
<div class="loadings__loader">
<div class="loadings__loader__dot"></div>
<div class="loadings__loader__dot"></div>
<div class="loadings__loader__dot"></div>
<div class="loadings__loader__dot"></div>
<div class="loadings__loader__dot"></div>
</div>
</div>
</transition>
</template>
<script type="text/babel">
export default {
data() {
return {
isShow: false,
hasAnimate: true,
}
},
computed: {
/**
* 動畫效果樣式,沒有傳回空
* @return {String} 樣式
*/
animateName() {
return this.hasAnimate ? 'opacity' : ''
},
},
methods: {
/**
* 開啟動畫效果
*/
opemAnimate() {
this.hasAnimate = true
},
/**
* 去除動畫效果
* @return {Promise} 傳回promise
*/
removeAnimate() {
return new Promise((resolve) => {
this.hasAnimate = false
resolve()
})
},
/**
* 顯示動畫loading
*/
show() {
this.isShow = true
},
/**
* 隐藏動畫loading
*/
hide() {
this.isShow = false
},
},
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scope>
.loadings {
position: fixed;
width: %;
height: %;
top: ;
left: ;
background: transparent;
&__loader {
position absolute
top 50%
left 50%
transform translate3d(-50%,-50%,0)
&__dot {
width 40px
height 40px
background #3ac
border-radius 100%
display inline-block
animation slide 1s infinite
margin-right: px;
for index in (1..5) {
&:nth-child({index}) {
animation-delay ( + s * index)
// background green(#ce2424, ( * index))
background lighten(#ce2424, (index * ))
}
}
}
}
}
@keyframes slide
%
transform scale()
%
opacity .
transform scale()
%
transform scale()
.opacity {
&-enter-active, &-leave-active {
transition: all s
}
&-enter, &-leave-active {
opacity:
}
}
</style>
這時如果你将其注冊為全局元件,也是可以使用的,但是前面我們說過,這樣使用非常不優雅
然後我們将其做成插件
// my-project/src/plugin/loading/index.js
import Loading from './loading.vue'
export default {
/**
* 每個插件都有的install方法,用于安裝插件
* @param {Object} Vue - Vue類
* @param {Object} [pluginOptions] - 插件安裝配置
*/
install(Vue, pluginOptions = {}) {
// 建立"子類"友善挂載
const VueLoading = Vue.extend(Loading)
let loading = null
/**
* 初始化并顯示loading
* @returns {Promise} Promise執行個體
*/
function $loading() {
return new Promise((resolve) => {
// 第一次調用
if (!loading) {
loading = new VueLoading()
// 手動建立一個未挂載的執行個體
loading.$mount()
// 挂載
document.querySelector(pluginOptions.container || 'body').appendChild(loading.$el)
}
// 顯示loading
loading.show()
resolve()
})
}
// 定義關閉loading方法
$loading.end = (noAnimate = false) => {
return new Promise((resolve) => {
if (!loading || !loading.isShow) {
resolve()
return
}
// 首頁判斷是否在關閉時需要動畫
if (noAnimate) {
// 預設隻在此次行為下移除動畫,之後的行為仍有動畫
loading.removeAnimate().then(() => {
loading.opemAnimate()
})
}
loading.hide()
})
}
Vue.loading = Vue.prototype.$loading = $loading
},
}
然後我們在入口檔案app.js中引入并且安裝插件就可以了:
···
import Vue from 'vue'
import VueLoading from './loading'
···
···
Vue.use(VueLoading, {
container: '.app',
})
···
接下來可以在你任意想要的地方執行this. loading()就可以啟動loading動畫了,在需要關閉的地方執行this. loading.end()就可以關閉咯
不信試試~