vue实现骨架屏的示例

骨架屏用途

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

Vue架构骨架屏

思路大纲

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

定义一个抽象组件

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

    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/* 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, 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实现骨架屏的资料请关注我们其它相关文章!

(0)

相关推荐

  • 基于 vue-skeleton-webpack-plugin 的骨架屏实战

    前言 目前正在做的项目,登录是需要跳转到别人的页面的,导致重定向很多,需要优化一下白屏时间,所以就用到了骨架屏,但是这次用的骨架屏不是自动生成的,还是自己敲的样式,一步步来吧,先从简单的用起 . 先上效果图: 什么是骨架屏 骨架屏,英文 Skeleton screen ,是指在页面开始渲染之前的白屏时间内,先让用户看到即将要展现页面的"骨架",页面渲染完成之后再将它替换掉,起到一个从 白屏 → 渲染完成 过程中的过渡作用,它可以有效减少用户的感知时间,让用户"感觉上"

  • vue 移动端注入骨架屏的配置方法

    什么是骨架屏? 简单的说,骨架屏就是在页面未渲染完成的时候,先用一些简单的图形大致勾勒出页面的基本轮廓,给用户造成页面正在加载的错觉,待页面渲染完成之后再用页面替换掉骨架屏,从而减少页面白屏的时间,给用户带来更好的体验.本文就是根据 page-skeleton-webpack-plugin 实现的骨架屏的实现,基于的是vue-cli3进行采坑 . 项目开始 安装依赖,package.json 配置vue.config.js 需要在新建vue.config.js,把之前的下载好的page-skel

  • 关于Vue单页面骨架屏实践记录

    关于骨架屏介绍 骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示.这样给用户一种很自然的过渡,不会造成页面长时间白屏或者闪烁等情况. 常见的骨架屏实现方案有ssr服务端渲染和prerender两种解决方案. 这里主要通过代码为大家展示如何一步步做出这样一个骨架屏: prerender 渲染骨架屏 本组件库骨架屏的实现也是基于预渲染去实现的,有关于预渲染更详细的介绍请参考这篇文章:处理 Vue 单页面 Meta SEO的另一种思路 下面我们主要介绍其实现步骤,首先我们

  • vue-cli 构建骨架屏的方法示例

    脚手架不说了,提前搭建好 然后安装 vue-skeleton-webpack-plugin npm install vue-skeleton-webpack-plugin 创建文件 skeleton.js和skeleton.vue skeleton.js import Vue from 'vue' import Skeleton from './Skeleton.vue' export default new Vue({ components: { Skeleton }, template: '

  • Vue页面骨架屏的实现方法

    在开发webapp的时候总是会受到首屏加载时间过长的影响,主流的解决方法是在载入完成之前显示loading图效果,而一些大公司会配置一套服务端渲染的架构来解决这个问题.考虑到ssr所要解决的一系列问题,越来越多的APP采用了"骨架屏"的方式去提升用户体验. 小米商城: 一.分析Vue页面的内容加载过程 vue项目中的入口index.html只有简单的内容: <!DOCTYPE html> <html lang="zh-CN"> <hea

  • 详解VUE单页应用骨架屏方案

    什么是骨架屏? 简单的说,骨架屏就是在页面未渲染完成的时候,先用一些简单的图形大致勾勒出页面的基本轮廓,给用户造成页面正在加载的错觉,待页面渲染完成之后再用页面替换掉骨架屏,从而减少页面白屏的时间,给用户带来更好的体验. 分析VUE渲染过程 使用vue-cli3.0创建项目: vue create project 在生成的项目文件夹下的public文件夹下的index.html文件代码如下: <!DOCTYPE html> <html lang="en"> &l

  • Vue页面骨架屏注入方法

    作为与用户联系最为密切的前端开发者,用户体验是最值得关注的问题.关于页面loading状态的展示,主流的主要有loading图和进度条两种.除此之外,越来越多的APP采用了"骨架屏"的方式去展示未加载内容,给予了用户焕然一新的体验.随着SPA在前端界的逐渐流行,首屏加载的问题也在困扰着开发者们.那么有没有一个办法,也能让SPA用上骨架屏呢?这就是这篇文章将要探讨的问题. 文章相关代码已经同步到 Github ,欢迎查阅~ 一.何为骨架屏 简单来说,骨架屏就是在页面内容未加载完成的时候,

  • 浅谈Vue项目骨架屏注入实践

    相比于早些年前后端代码紧密耦合.后端工程师还得写前端代码的时代,如今已发展到前后端分离,这种开发方式大大提升了前后端项目的可维护性与开发效率,让前后端工程师关注于自己的主业.然而在带来便利的同时,也带来了一些弊端,比如首屏渲染时间(FCP)因为首屏需要请求更多内容,比原来多了更多HTTP的往返时间(RTT),这造成了白屏,如果白屏时间过长,用户体验会大打折扣,如果用户网速差,则FCP会更长. 由此引申出一系列的优化方法,骨架屏也因此被提出. 1. FCP优化 在 Google 提出的以用户为中心

  • vue实现骨架屏的示例

    骨架屏用途 作为spa中路由切换的 loading, 结合组件的生命周期和ajax请求返回的时机来使用.( 作为loading 使用).作为与用户联系最为密切的前端开发者,用户体验是最值得关注的问题.关于页面loading状态的展示,主流的主要有loading图和进度条两种.除此之外,越来越多的APP采用了"骨架屏"的方式去展示未加载内容,给予了用户焕然一新的体验. 作为首屏渲染的优化 Vue架构骨架屏 思路大纲 定义一个抽象组件,在抽象组件的render函数里获取插槽 深度循环遍历插

  • React实现一个通用骨架屏组件示例

    目录 骨架屏是什么? Demo 设计思路 具体实现 骨架屏是什么? 找到这里的同志,或多或少都对骨架屏有所了解,请容许我先啰嗦一句.骨架屏(Skeleton Screen)是一种优化用户弱网体验的方案,可以有效缓解用户等待的焦躁情绪. Demo 先看个demo 大概了解下最终的产物及其使用方式 npm install obiusm-react-components import { Skeleton } from 'obiusm-react-components'; <Skeleton isVi

  • vue项目中使用骨架屏的方法

    现在的应用开发,基本上都是前后端分离的,前端主流框架有SPA.MPA等,那么解决页面渲染.白屏时间成为首要关注的点 webpack可以按需加载,减小首屏需要加载代码的体积: 使用CDN技术.静态代码等缓存技术,可以减小加载渲染的时长 问题:但是首页依然存在加载.渲染等待时长的问题.那么如何从视觉效果上减小首屏白屏的时间呢? 骨架屏:举个例子:其实就是在模版文件中id=app容器下面写想要展示的效果,在new Vue(option)之后,该id下的内容就被替换了( 这时候,可能Vue编译生成的内容

随机推荐