文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

vue实现骨架屏的示例

2024-04-02 19:55

关注

骨架屏用途

Vue架构骨架屏

思路大纲

定义一个抽象组件

什么是抽象组件? 在渲染时会被跳过,只做运行时的操作的组件


    export default {
      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, 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, handler, false)
    },
    handlerPrefix(slots, handler, 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, handler, 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 {
            slot.elm.textContent = slot.memorizedtextContent || slot.elm.textContent || slot.text
          }
        }
        children && this.handlerPrefix(children, handler, 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 && rootVnode.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包裹,如上的使用方法,以下是一个简单的例子

完整地址

80行代码实现Vue骨架屏

以上就是vue实现骨架屏的示例的详细内容,更多关于vue实现骨架屏的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯