您好,登錄后才能下訂單哦!
這篇文章主要講解了“即插即用的Vue Loading插件怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“即插即用的Vue Loading插件怎么實現(xiàn)”吧!
無論最終要實現(xiàn)怎樣的網(wǎng)站,Loading狀態(tài)都是必不可少的一環(huán),給用戶一個過渡喘息的機會也給服務器一個遞達響應的時間。
從使用方式說起
不管從0開始寫起還是直接下載的Loading插件,都會抽象為一個組件,在用到的時候進行加載Loading,或者通過API手動進行show或者hide
<wait> </wait> ... this.$wait.show() await fetch('http://example.org') this.$wait.hide()
或者通過Loading狀態(tài)進行組件間的切換
<loader v-if="isLoading"> </loader> <Main v-else> </Main>
要想注冊成全局狀態(tài),還需要給axios類的網(wǎng)絡請求包添加攔截器,然后設置一個全局Loading狀態(tài),每次有網(wǎng)絡請求或者根據(jù)已經(jīng)設置好的URL將Loading狀態(tài)設置為加載,請求完成后在設置為完成。
注冊axios攔截器:
let loadingUrls = [ `${apiUrl}/loading/`, `${apiUrl}/index/`, `${apiUrl}/comments/`, ... ] axios.interceptors.request.use((config) => { let url = config.url if (loadingUrls.indexOf('url') !== -1) { store.loading.isLoading = true } }) axios.interceptors.response.use((response) => { let url = response.config.url if (loadingUrls.indexOf('url') !== -1) { store.loading.isLoading = false } })
使用時在每個組件下獲取出loading狀態(tài),然后判斷什么時候顯示loading,什么時候顯示真正的組件。
<template> <div> <loader v-if="isLoading"> </loader> <Main v-else> </Main> </div> </template> <script> ... components: { loader }, computed: { isLoading: this.$store.loading.isLoading }, async getMainContent () { // 實際情況下State僅能通過mutations改變. this.$sotre.loading.isLoading = false await axios.get('...') this.$sotre.loading.isLoading = false }, async getMain () { await getMainContent() } ... </script>
在當前頁面下只有一個需要Loading的狀態(tài)時使用良好,但如果在同一個頁面下有多個不同的組件都需要Loading,你還需要根據(jù)不同組件進行標記,好讓已經(jīng)加載完的組件不重復進入Loading狀態(tài)...隨著業(yè)務不斷增加,重復進行的Loading判斷足以讓人煩躁不已...
整理思路
Loading的核心很簡單,就是請求服務器時需要顯示Loading,請求完了再還原回來,這個思路實現(xiàn)起來并不費力,只不過使用方式上逃不開上面的顯式調(diào)用的方式。順著思路來看,能進行Loading設置的地方有,
設置全局攔截,請求開始前設置狀態(tài)為加載。
設置全局攔截,請求結束后設置狀態(tài)為完成。
在觸發(fā)請求的函數(shù)中進行攔截,觸發(fā)前設置為加載,觸發(fā)后設置為完成。
判斷請求后的數(shù)據(jù)是否為非空,如果非空則設置為完成
最終可以實現(xiàn)的情況上,進行全局攔截設置,然后局部的判斷是最容易想到也是最容易實現(xiàn)的方案。給每個觸發(fā)的函數(shù)設置before
和after
看起來美好,但實現(xiàn)起來簡直是災難,我們并沒有before
和after
這兩個函數(shù)鉤子來告訴我們函數(shù)什么時候調(diào)用了和調(diào)用完了,自己實現(xiàn)吧坑很多,不實現(xiàn)吧又沒得用只能去原函數(shù)里一個個寫上。只判斷數(shù)據(jù)局限性很大,只有一次機會。
既然是即插即用的插件,使用起來就得突出一個簡單易用,基本思路上也是使用全局攔截,但局部判斷方面與常規(guī)略有不同,使用數(shù)據(jù)綁定(當然也可以再次全局響應攔截),咱們實現(xiàn)起來吧~。
樣式
Loading嘛,必須得有一個轉圈圈才能叫Loading,樣式并不是這個插件的最主要的,這里直接用CSS實現(xiàn)一個容易實現(xiàn)又不顯得很糙的:
<template> <div class="loading"> </div> </template> ... <style scoped> .loading { width: 50px; height: 50px; border: 4px solid rgba(0,0,0,0.1); border-radius: 50%; border-left-color: red; animation: loading 1s infinite linear; } @keyframes loading { 0% { transform: rotate(0deg) } 100% { transform: rotate(360deg) } } </style>
固定大小50px的正方形,使用border-radius
把它盤得圓潤一些,border
設置個進度條底座,border-left-color
設置為進度條好了。
綁定數(shù)據(jù)與URL
提供外部使用接口
上面思路中提到,這個插件是用全局攔截與數(shù)據(jù)綁定制作的:
暴露一個 source 屬性,從使用的組件中獲取出要綁定的數(shù)據(jù)。
暴露一個 urls 屬性,從使用的組件中獲取出要攔截的URL。
<template> ... </template> <script> export default { props: { source: { require: true }, urls: { type: Array, default: () => { new Array() } } }, data () { return { isLoading: true } }, watch: { source: function () { if (this.source) { this.isLoading = false } } } } </script> <style scoped> .... </style>
不用關心source是什么類型的數(shù)據(jù),我們只需要監(jiān)控它,每次變化時都將Loading狀態(tài)設置為完成即可,urls我們稍后再來完善它。
設置請求攔截器
攔截器中需要的操作是將請求時的每個URL壓入一個容器內(nèi),請求完再把它刪掉。
Vue.prototype.__loader_checks = [] Vue.prototype.$__loadingHTTP = new Proxy({}, { set: function (target, key, value, receiver) { let oldValue = target[key] if (!oldValue) { Vue.prototype.__loader_checks.forEach((func) => { func(key, value) }) } return Reflect.set(target, key, value, receiver) } }) axios.interceptors.request.use(config => { Vue.prototype.$__loadingHTTP[config.url] = config return config }) axios.interceptors.response.use(response => { delete Vue.prototype.$__loadingHTTP[response.config.url] return response })
將其掛載在Vue實例上,方便我們之后進行調(diào)用,當然還可以用Vuex,但此次插件要突出一個依賴少,所以Vuex還是不用啦。
直接掛載在Vue上的數(shù)據(jù)不能通過computed
或者watch
來監(jiān)控數(shù)據(jù)變化,咱們用Proxy
代理攔截set
方法,每當有請求URL壓入時就做點什么事。Vue.prototype.__loader_checks
用來存放哪些實例化出來的組件訂閱了請求URL時做加載的事件,這樣每次有URL壓入時,通過Proxy
來分發(fā)給訂閱過得實例化Loading組件。
訂閱URL事件
<template> ... </template> <script> export default { props: { source: { require: true }, urls: { type: Array, default: () => { new Array() } } }, data () { return { isLoading: true } }, watch: { source: function () { if (this.source) { this.isLoading = false } } }, mounted: function () { if (this.urls) { this.__loader_checks.push((url, config) => { if (this.urls.indexOf(url) !== -1) { this.isLoading = true } }) } } } </script> <style scoped> .... </style>
每一個都是一個嶄新的實例,所以直接在mounted里訂閱URL事件即可,只要有傳入urls
,就對__loader_checks
里每一個訂閱的對象進行發(fā)布,Loader實例接受到發(fā)布后會判斷這個URL是否與自己注冊的對應,對應的話會將自己的狀態(tài)設置回加載,URL請求后勢必會引起數(shù)據(jù)的更新,這時我們上面監(jiān)控的source
就會起作用將加載狀態(tài)設置回完成。
使用槽來適配原來的組件
寫完上面這些你可能有些疑問,怎么將Loading時不應該顯示的部分隱藏呢?答案是使用槽來適配,
<template> <div> <div class="loading" v-if="isLoading" :key="'loading'"> </div> <slot v-else> </slot> </div> </template> <script> export default { props: { source: { require: true }, urls: { type: Array, default: () => { new Array() } } }, data () { return { isLoading: true } }, watch: { source: function () { if (this.source) { this.isLoading = false } } }, mounted: function () { if (this.urls) { this.__loader_checks.push((url, config) => { if (this.urls.indexOf(url) !== -1) { this.isLoading = true } }) } } } </script> <style scoped> .... </style>
還是通過isLoading
判斷,如果處于加載那顯示轉圈圈,否則顯示的是父組件里傳入的槽,
這里寫的要注意,Vue這里有一個奇怪的BUG,
<div class="loading" v-if="isLoading" :key="'loading'"> </div> <slot v-else> </slot>
在有<slot>
時,如果同級的標簽同時出現(xiàn)v-if
與CSS選擇器
且樣式是scoped
,那用CSS選擇器
設置的樣式將會丟失,<div v-if="isLoading" :key="'loading'">
如果沒有設置key
那.loading
的樣式會丟失,除了設置key
還可以把它變成嵌套的<div v-if="isLoading"> <div></div> </div>
。
注冊成插件
Vue中的插件有四種注冊方式,這里用mixin來混入到每個實例中,方便使用,同時我們也把上面的axios攔截器也注冊在這里。
import axios import Loader from './loader.vue' export default { install (Vue, options) { Vue.prototype.__loader_checks = [] Vue.prototype.$__loadingHTTP = new Proxy({}, { set: function (target, key, value, receiver) { let oldValue = target[key] if (!oldValue) { Vue.prototype.__loader_checks.forEach((func) => { func(key, value) }) } return Reflect.set(target, key, value, receiver) } }) axios.interceptors.request.use(config => { Vue.prototype.$__loadingHTTP[config.url] = config return config }) axios.interceptors.response.use(response => { delete Vue.prototype.$__loadingHTTP[response.config.url] return response }) Vue.mixin({ beforeCreate () { Vue.component('v-loader', Loader) } }) } }
使用
在入口文件中使用插件
import Loader from './plugins/loader/index.js' ... Vue.use(Loader) ...
任意組件中無需導入即可使用
<v-loader :source="msg" :urls="['/']"> <div @click="getRoot">{{ msg }}</div> </v-loader>
根據(jù)綁定的數(shù)據(jù)和綁定的URL自動進行Loading的顯示與隱藏,無需手動設置isLoading
是不是該隱藏,也不用調(diào)用show
與hide
在請求的方法里打補丁。
其他
上面的通過綁定數(shù)據(jù)來判斷是否已經(jīng)響應,如果請求后的數(shù)據(jù)不會更新,那你也可以直接在axios的response里做攔截進行訂閱發(fā)布模式的響應。
Vue是一款友好的、多用途且高性能的JavaScript框架,使用vue可以創(chuàng)建可維護性和可測試性更強的代碼庫,Vue允許可以將一個網(wǎng)頁分割成可復用的組件,每個組件都包含屬于自己的HTML、CSS、JavaScript,以用來渲染網(wǎng)頁中相應的地方,所以越來越多的前端開發(fā)者使用vue。
感謝各位的閱讀,以上就是“即插即用的Vue Loading插件怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對即插即用的Vue Loading插件怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。