中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何寫一個即插即用的Vue Loading插件

發布時間:2021-06-05 15:25:30 來源:億速云 閱讀:150 作者:小新 欄目:web開發

這篇文章主要介紹了如何寫一個即插即用的Vue Loading插件,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

無論最終要實現怎樣的網站,Loading狀態都是必不可少的一環,給用戶一個過渡喘息的機會也給服務器一個遞達響應的時間。

從使用方式說起

不管從0開始寫起還是直接下載的Loading插件,都會抽象為一個組件,在用到的時候進行加載Loading,或者通過API手動進行show或者hide

<wait>
</wait>
...
this.$wait.show()
await fetch('http://example.org')
this.$wait.hide()

或者通過Loading狀態進行組件間的切換

<loader v-if="isLoading">
</loader>
<Main v-else>
</Main>

。要想注冊成全局狀態,還需要給axios類的網絡請求包添加攔截器,然后設置一個全局Loading狀態,每次有網絡請求或者根據已經設置好的URL將Loading狀態設置為加載,請求完成后在設置為完成。

注冊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狀態,然后判斷什么時候顯示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的狀態時使用良好,但如果在同一個頁面下有多個不同的組件都需要Loading,你還需要根據不同組件進行標記,好讓已經加載完的組件不重復進入Loading狀態...隨著業務不斷增加,重復進行的Loading判斷足以讓人煩躁不已...

整理思路

Loading的核心很簡單,就是請求服務器時需要顯示Loading,請求完了再還原回來,這個思路實現起來并不費力,只不過使用方式上逃不開上面的顯式調用的方式。順著思路來看,能進行Loading設置的地方有,

  • 設置全局攔截,請求開始前設置狀態為加載。

  • 設置全局攔截,請求結束后設置狀態為完成。

  • 在觸發請求的函數中進行攔截,觸發前設置為加載,觸發后設置為完成。

  • 判斷請求后的數據是否為非空,如果非空則設置為完成

最終可以實現的情況上,進行全局攔截設置,然后局部的判斷是最容易想到也是最容易實現的方案。給每個觸發的函數設置beforeafter看起來美好,但實現起來簡直是災難,我們并沒有beforeafter這兩個函數鉤子來告訴我們函數什么時候調用了和調用完了,自己實現吧坑很多,不實現吧又沒得用只能去原函數里一個個寫上。只判斷數據局限性很大,只有一次機會。

既然是即插即用的插件,使用起來就得突出一個簡單易用,基本思路上也是使用全局攔截,但局部判斷方面與常規略有不同,使用數據綁定(當然也可以再次全局響應攔截),咱們實現起來吧~。

樣式

Loading嘛,必須得有一個轉圈圈才能叫Loading,樣式并不是這個插件的最主要的,這里直接用CSS實現一個容易實現又不顯得很糙的:

<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設置為進度條好了。

演示地址

如何寫一個即插即用的Vue Loading插件

綁定數據與URL

提供外部使用接口

上面思路中提到,這個插件是用全局攔截與數據綁定制作的:

  • 暴露一個 source 屬性,從使用的組件中獲取出要綁定的數據。

  • 暴露一個 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是什么類型的數據,我們只需要監控它,每次變化時都將Loading狀態設置為完成即可,urls我們稍后再來完善它。

設置請求攔截器

攔截器中需要的操作是將請求時的每個URL壓入一個容器內,請求完再把它刪掉。

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實例上,方便我們之后進行調用,當然還可以用Vuex,但此次插件要突出一個依賴少,所以Vuex還是不用啦。

直接掛載在Vue上的數據不能通過computed或者watch來監控數據變化,咱們用Proxy代理攔截set方法,每當有請求URL壓入時就做點什么事。Vue.prototype.__loader_checks用來存放哪些實例化出來的組件訂閱了請求URL時做加載的事件,這樣每次有URL壓入時,通過Proxy來分發給訂閱過得實例化Loading組件。

如何寫一個即插即用的Vue 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里每一個訂閱的對象進行發布,Loader實例接受到發布后會判斷這個URL是否與自己注冊的對應,對應的話會將自己的狀態設置回加載,URL請求后勢必會引起數據的更新,這時我們上面監控的source就會起作用將加載狀態設置回完成。

如何寫一個即插即用的Vue Loading插件

使用槽來適配原來的組件

寫完上面這些你可能有些疑問,怎么將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>時,如果同級的標簽同時出現v-ifCSS選擇器且樣式是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>

根據綁定的數據和綁定的URL自動進行Loading的顯示與隱藏,無需手動設置isLoading是不是該隱藏,也不用調用showhide在請求的方法里打補丁。

其他

上面的通過綁定數據來判斷是否已經響應,如果請求后的數據不會更新,那你也可以直接在axios的response里做攔截進行訂閱發布模式的響應。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“如何寫一個即插即用的Vue Loading插件”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

庄河市| 华蓥市| 武鸣县| 涿鹿县| 安达市| 时尚| 沙田区| 沙雅县| 青海省| 嘉黎县| 云浮市| 棋牌| 桂阳县| 海淀区| 元谋县| 炎陵县| 玉田县| 乐安县| 黔东| 九寨沟县| 隆子县| 交口县| 清徐县| 乐平市| 商城县| 龙山县| 明光市| 胶州市| 定襄县| 安阳县| 萨嘎县| 会昌县| 兰溪市| 塘沽区| 宾阳县| 内黄县| 平和县| 黄大仙区| 商洛市| 东平县| 阳城县|