1. 程式人生 > 程式設計 >vue實現骨架屏的示例

vue實現骨架屏的示例

骨架屏用途

  • 作為spa中路由切換的 loading,結合元件的生命週期和ajax請求返回的時機來使用.( 作為loading 使用)。作為與使用者聯絡最為密切的前端開發者,使用者體驗是最值得關注的問題。關於頁面loading狀態的展示,主流的主要有loading圖和進度條兩種。除此之外,越來越多的APP採用了“骨架屏”的方式去展示未載入內容,給予了使用者煥然一新的體驗。
  • 作為首屏渲染的優化

vue架構骨架屏

思路大綱

  • 定義一個抽象元件,在抽象元件的render函式裡獲取插槽
  • 深度迴圈遍歷插槽,將每個元素都新增上gm-skeleton的類名
  • 將vnode textContent預暫後清空保證骨架屏出現時不會出現預設文字
  • 返回slots

定義一個抽象元件

什麼是抽象元件? 在渲染時會被跳過,只做執行時的操作的元件

    export def程式設計客棧ault {
      name: 'GmSkeleton',abstract: true // 抽象元件的屬性
    }

獲取插槽並初始化操作骨架屏

    render(h) {
      const slots = this.$slots.default || [h('')]
      this.$nextTick().then(() => {
        this.handlerPrefix(slots,this.showSpin ? this.addSkeletPrefix : this.removeSkeletPrefix)
      })

      return slots.length > 1 ? h('div',{
         staticClass: this.showSpin ? 'g-spinner' : ''
      },slots) : slots
    }

這裡我們將處理slots的方法放置在nextTick裡面,因為handlerPrefix裡需要獲取真實的DOM,nextTick是用來執行排序後的更新佇列裡的所有方法,在執行render前,GMSkeleton元件的renderWatcher已被收集到更新佇列裡,所以此時定義nextTick CallBack函式裡能獲取到渲染後對應插槽裡所有真實DOM,若是不瞭解nextTick原理,請移步你不知道的nextTick

迴圈slots操作類名

    handlerComponent(slot,handler/* addSkeletPrefix | removeSkeletPrefix */,init) {
      const originchildren = (((slot.componentInstance || {})._vnode || {}).componentOptions || {}).children
      const compchildren = ((slot.componentInstance || {})._vnode || {}).children
      !init && handler(slot)
      if (compchildren) this.handlerPrefix(compchildren,handler,false)
      if (originchildren) this.handlerPrefix(originchildren,false)
    },handlerPrefix(slots,init = true) {
      slots.forEach(slot => {
        var children = slot.children || (slot.componentOptions || {}).children || ((slot.componentInstance || {})._vnode || {}).children
        if (slot.data) {
          if (!slot.componentOptions) {
            !init && handler(slot)
          } else if (!this.$hoc_utils.getAbstractComponent(slot)) {
            ;(function
程式設計客棧
(slot) { const handlerComponent = this.handlerComponent.bind(this,slot,init) const insert = (slot.data.hook || {}).insert ;(slot.data.hook || {}).insert = () => { // 函式重構,修改原有的元件hook,並且保證insert只執行一次 insert(slot) handlerComponent() } ;(slot.data.hook || {}).postpatch = handlerComponent }).call(this,slot) } } if (slot && slot.elm && slot.elm.nodeType === 3) { if (this.showSpin) { slot.memorizedtextContent = slot.elm.textContent slot.elm.textContent = '' } else { BdEbjeXksK slot.elm.textContent = slot.memorizedtextContent || slot.elm.textContent || slot.text } } children && this.handlerPrefix(children,false) }) },

逐步分析:

  1. 我們遍歷slots插槽
  2. 獲取當前vnode下的children集合以備做下一次迴圈
  3. 判斷是否是原生HTML元素,只有元件vnode才會具備componentOptions屬性
  4. 判斷是否抽象元件,我們知道抽象元件是不會渲染到真實DOMTree上的,例如keep-alive、transition,每個元件的vnode擁有獨有的hooks生命週期: init(初始化)、insert(插入)、prepatch(更新)、destroy(銷燬),每個生命週期會在不同階段觸發,劫持insert,保留原有的insert方法,隨後重構vnode的insert方法在裡面呼叫handlerComponent方法進行新增類名,這裡與上面的mounted的nextTick用法理念類似,由於handlerComponent需要知道子元件的例項,所以必須在例項化後去呼叫,而元件的init方法會例項元件並且直接呼叫watcher.update(watcher.render()),也就是我們在呼叫insert方法的時候其實是在update(render())後,所以這裡能夠獲取到例項化後子元件
  5. 判斷nodeType是否是文字節點,若是的話需要先將textContent儲存後進行刪除,保證在骨架屏出現時不會顯示預設文字,在骨架屏消失時,將原先保留的預設文字返回給vnode,這樣就能自由在骨架屏的顯示隱藏期間自由切換

操作vnode的靜態類名

    addSkeletPrefix(slot) {
      const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
      if (rootVnode.elm) {
        rootVnode.elm.classList.add(this.skeletPrefix)
      } else {
        ;(rootVnode.data || {}).staticClass += ` ${this.skeletPrefix}`
      }
    },removeSkeletPrefix(slot) {
      const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
      if (rootVnode.elm) {
        rootVnode.elm.classList && rohttp://www.cppcns.comotVnode.elm.classList.remove(this.skeletPrefix)
      } else if (rootVnode.data.staticClass) {
        rootVnode.data.staticClass = rootVnode.data.staticClass.replace(` ${this.skeletPrefix}`,'')
      }
    }

addSkeletePrefix用於新增gm-skeleton類名,而removeSkeletonPrefix則是用於刪除gm-skeleton類名

使用方法

  import Vue from 'vue'
  import GMSkeleton from 'path/to/GMSkeleton'
  
  Vue.use(GMSkeleton)
  <gm-skeleton>
    <Component />
    <div></div>
    <div><span>前端馬丁</span></div>
  </gm-skeleton>

傳值

屬性名 描述
showSpin Boolean 是否開啟骨架屏,預設為true
skeletPrefix String 骨架屏類名,預設是gm-skeleton

效果如下

具體樣式是根據開發者自己寫的樣式來生成的,通過gm-skeleton包裹,如上的使用方法,以下是一個簡單的例子

vue實現骨架屏的示例

完整地址

80行程式碼實現Vue骨架屏

以上就是vue實現骨架屏的示例的詳細內容,更多關於vue實現骨架www.cppcns.com屏的資料請關注我們其它相關文章!