• 售前

  • 售后

热门帖子
入门百科

vue实现骨架屏的示例

[复制链接]
二级传播盅 显示全部楼层 发表于 2021-10-26 13:56:02 |阅读模式 打印 上一主题 下一主题
目次


  • 骨架屏用途
  • Vue架构骨架屏

    • 思绪大纲
    • 界说一个抽象组件
    • 获取插槽并初始化使用骨架屏
    • 循环slots使用类名
    • 使用vnode的静态类名

  • 使用方法

    • 传值
    • 结果如下

  • 完整地址

骨架屏用途


       
  • 作为spa中路由切换的 loading, 团结组件的生命周期和ajax哀求返回的机遇来使用.( 作为loading 使用)。作为与用户接洽最为密切的前端开辟者,用户体验是最值得关注的问题。关于页面loading状态的展示,主流的紧张有loading图和进度条两种。除此之外,越来越多的APP采取了“骨架屏”的方式去展示未加载内容,给予了用户焕然一新的体验。   
  • 作为首屏渲染的优化

Vue架构骨架屏



思绪大纲


       
  • 界说一个抽象组件,在抽象组件的render函数里获取插槽   
  • 深度循环遍历插槽,将每个元素都添加上gm-skeleton的类名   
  • 将vnode textContent预暂后清空包管骨架屏出现时不会出现默认笔墨   
  • 返回slots

界说一个抽象组件


什么是抽象组件? 在渲染时会被跳过,只做运行时的使用的组件
  1.     export default {
  2.       name: 'GmSkeleton',
  3.       abstract: true // 抽象组件的属性
  4.     }
复制代码
获取插槽并初始化使用骨架屏
  1.     render(h) {
  2.       const slots = this.$slots.default || [h('')]
  3.       this.$nextTick().then(() => {
  4.         this.handlerPrefix(slots, this.showSpin ? this.addSkeletPrefix : this.removeSkeletPrefix)
  5.       })
  6.       return slots.length > 1 ? h('div', {
  7.          staticClass: this.showSpin ? 'g-spinner' : ''
  8.       }, slots) : slots
  9.     }
复制代码
这里我们将处理slots的方法放置在nextTick内里, 由于handlerPrefix里必要获取真实的DOM,nextTick是用来实行排序后的更新队列里的所有方法, 在实行render前, GMSkeleton组件的renderWatcher已被网络到更新队列里,以是此时界说nextTick CallBack函数里能获取到渲染后对应插槽里所有真实DOM,如果不相识nextTick原理,请移步你不知道的nextTick

循环slots使用类名
  1.     handlerComponent(slot, handler/* addSkeletPrefix | removeSkeletPrefix */, init) {
  2.       const originchildren = (((slot.componentInstance || {})._vnode || {}).componentOptions || {}).children
  3.       const compchildren = ((slot.componentInstance || {})._vnode || {}).children
  4.       !init && handler(slot)
  5.       if (compchildren) this.handlerPrefix(compchildren, handler, false)
  6.       if (originchildren) this.handlerPrefix(originchildren, handler, false)
  7.     },
  8.     handlerPrefix(slots, handler, init = true) {
  9.       slots.forEach(slot => {
  10.         var children = slot.children || (slot.componentOptions || {}).children || ((slot.componentInstance || {})._vnode || {}).children
  11.         if (slot.data) {
  12.           if (!slot.componentOptions) {
  13.             !init && handler(slot)
  14.           } else if (!this.$hoc_utils.getAbstractComponent(slot)) {
  15.             ;(function(slot) {
  16.               const handlerComponent = this.handlerComponent.bind(this, slot, handler, init)
  17.               const insert = (slot.data.hook || {}).insert
  18.               ;(slot.data.hook || {}).insert = () => { // 函数重构, 修改原有的组件hook, 并且保证insert只执行一次
  19.                 insert(slot)
  20.                 handlerComponent()
  21.               }
  22.               ;(slot.data.hook || {}).postpatch = handlerComponent
  23.             }).call(this, slot)
  24.           }
  25.         }
  26.         if (slot && slot.elm && slot.elm.nodeType === 3) {
  27.           if (this.showSpin) {
  28.             slot.memorizedtextContent = slot.elm.textContent
  29.             slot.elm.textContent = ''
  30.           } else {
  31.             slot.elm.textContent = slot.memorizedtextContent || slot.elm.textContent || slot.text
  32.           }
  33.         }
  34.         children && this.handlerPrefix(children, handler, false)
  35.       })
  36.     },
复制代码
渐渐分析:
       
  • 我们遍历slots插槽   
  • 获取当前vnode下的children聚集以备做下一次循环   
  • 判定是否是原生HTML元素,只有组件vnode才会具备componentOptions属性   
  • 判定是否抽象组件,我们知道抽象组件是不会渲染到真实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())后,以是这里可以或许获取到实例化后子组件   
  • 判定nodeType是否是文本节点,如果的话必要先将textContent保存后进行删除,包管在骨架屏出现时不会表现默认笔墨,在骨架屏消失时,将原先保留的默认笔墨返回给vnode,如许就能自由在骨架屏的表现隐蔽期间自由切换

使用vnode的静态类名
  1.     addSkeletPrefix(slot) {
  2.       const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
  3.       if (rootVnode.elm) {
  4.         rootVnode.elm.classList.add(this.skeletPrefix)
  5.       } else {
  6.         ;(rootVnode.data || {}).staticClass += ` ${this.skeletPrefix}`
  7.       }
  8.     },
  9.     removeSkeletPrefix(slot) {
  10.       const rootVnode = slot.componentOptions ? (slot.componentInstance || {})._vnode || {} : slot;
  11.       if (rootVnode.elm) {
  12.         rootVnode.elm.classList && rootVnode.elm.classList.remove(this.skeletPrefix)
  13.       } else if (rootVnode.data.staticClass) {
  14.         rootVnode.data.staticClass = rootVnode.data.staticClass.replace(` ${this.skeletPrefix}`, '')
  15.       }
  16.     }
复制代码
addSkeletePrefix用于添加gm-skeleton类名,而removeSkeletonPrefix则是用于删除gm-skeleton类名

使用方法
  1.   import Vue from 'vue'
  2.   import GMSkeleton from 'path/to/GMSkeleton'
  3.   
  4.   Vue.use(GMSkeleton)
复制代码
  1.   <gm-skeleton>
  2.     <Component />
  3.     <div></div>
  4.     <div><span>前端马丁</span></div>
  5.   </gm-skeleton>
复制代码
传值

            属性名            值            描述                                    showSpin            Boolean            是否开启骨架屏,默以为true                            skeletPrefix            String            骨架屏类名, 默认是gm-skeleton        

结果如下


具体样式是根据开辟者自己写的样式来天生的,通过gm-skeleton包裹,如上的使用方法,以下是一个简单的例子


完整地址


80行代码实现Vue骨架屏
以上就是vue实现骨架屏的示例的具体内容,更多关于vue实现骨架屏的资料请关注草根技术分享别的干系文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作