骨架屏技术讲解以及如何在Vue中实现骨架屏

article/2025/9/15 4:28:22

骨架屏技术讲解以及如何在Vue中实现骨架屏

  • 写在前面
  • 骨架屏是什么
  • 如何实现(原理分析)
    • 一个生动的例子
  • 实现方式(具体实现)
    • 方案一、在模版中来实现骨架屏
    • 方案二、使用一个Base64的图片来作为骨架屏
    • 方案三、使用 .vue 文件来完成骨架屏
    • 方案四、自动生成并自动插入静态骨架屏

写在前面

现在的前端开发领域,都是前后端分离,前端框架主流的都是 SPAMPA;这就意味着,页面渲染以及等待的白屏时间,成为我们需要解决的问题点;而且大项目,这个问题尤为突出。

webpack 可以实现按需加载,减小我们首屏需要加载的代码体积;再配合上 CDN 以及一些静态代码(框架,组件库等等…)缓存技术,可以很好的缓解这个加载渲染的时间过长的问题。

但即便如此,首屏的加载依然还是存在这个加载以及渲染的等待时间问题;

骨架屏是什么

目前主流,常见的解决方案是使用骨架屏技术,包括很多原生的APP,在页面渲染时,也会使用骨架屏。(下图中,红圈中的部分,即为骨架屏在内容还没有出现之前的页面骨架填充,以免留白

如何实现(原理分析)

在 Vue 中,我们是通过 $mount 实例方法去挂载 vm 的;我们来简单看一下 Vue 代码里面关于 $mount 方法的实现:

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (el?: string | Element,hydrating?: boolean
): Component {el = el && query(el)/* istanbul ignore if */if (el === document.body || el === document.documentElement) {process.env.NODE_ENV !== 'production' && warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`)return this}const options = this.$options// resolve template/el and convert to render functionif (!options.render) {...}return mount.call(this, el, hydrating)
}

我们可以看到:这段代码首先缓存了原型上的 $mount 方法,再重新定义该方法,我们先来分析这段代码。首先,它对 el 做了限制,Vue 不能挂载在 body、html 这样的根节点上。为什么??

因为render生成的vNode,通过 $mount 方法,挂载在我们的定义的 DOM 元素上;这里的挂载是【替换】的意思。

默认情况下我们的模版 index.html 里面有一个 id 为 app 的 div 元素。我们最终的应用程序代码会替换掉这个元素,也就是 <div id="app"></div>;对,我们 Vue 渲染出来的内容是替换掉它,而不是插入在这个节点中。

这也就是 Vue 不能挂载在 body、html 这样的根节点的原因。你总不能把 body、html 这样的元素节点替换掉把。

知识点补充:
如果没有定义 render 方法,则会把 el 或者 template 字符串转换成 render 方法。这里我们要牢记,在 Vue 2.0 版本中,所有 Vue 的组件的渲染最终都需要 render 方法,无论我们是用单文件 .vue 方式开发组件,还是写了 el 或者 template 属性,最终都会转换成 render 方法,那么这个过程是 Vue 的一个“在线编译”的过程,它是调用 compileToFunctions 方法实现的。最后,调用原先原型上的 $mount 方法挂载。

参考: Vue 实例挂载的实现

一个生动的例子

在这里插入图片描述

我们模版(index.html)里面的内容是这样的:

<body><div id="app"><span style="color: red;font-size: 34px;">你好</span></div><!-- built files will be auto injected -->
</body>

模版里面的挂载点是 div#appApp.vue 里面的根节点是 div#app-two,渲染完成以后,页面上的 div#app 就变成了 div#app-two

那么,这里分析总结出来的最重要的一点就是:Vue 的 $mount 方法挂载元素,采用的是【替换】模版中的挂载点 这样的方法,知道了这个知识点以后,我们要实现骨架屏,就有了很好的实现思路了。

实现方式(具体实现)

方案一、在模版中来实现骨架屏

思路:在 index.html 中的 div#app 中来实现骨架屏,程序渲染后就会替换掉 index.html 里面的 div#app 骨架屏内容;

在这里插入图片描述
ok,做完了;你觉得我这个骨架屏做的怎么样。

方案二、使用一个Base64的图片来作为骨架屏

使用图片作为骨架屏; 简单暴力,让UI同学花点功夫吧;小米商城的移动端页面采用的就是这个方法,它是使用了一个Base64的图片来作为骨架屏。

按照方案一的方案,将这个 Base64 的图片写在我们的 index.html 模块中的 div#app 里面。

方案三、使用 .vue 文件来完成骨架屏

我们可能不希望在默认的模版(index.html)上来进行代码的coding;想在方案一的基础上,将骨架屏的代码抽离出来,使用一个 .vue 文件来 coding,易于维护。

1、我们在 src 下建一个 skeleton 目录,在里面创建两个文件(skeleton.vueskeleton.entry.js);skeleton.vue 就是我们的骨架屏页面的代码,skeleton.entry.js 是编译 skeleton.vue 的入口文件,类似于我们 Vue 项目中的 main.js 文件;

// skeleton.entry.js
import Vue from 'vue'
import Skeleton from './skeleton.vue'export default new Vue({// 根实例简单的渲染应用程序组件render: h => h(Skeleton)
})
<!-- skeleton.vue -->
<template><div class="skeleton page"><span>骨架屏</span></div>
</template><style scoped>
</style>

2、我们还需要在新建一个 webpack.skeleton.conf.js 文件,以专门用来进行骨架屏的构建(这个文件放在哪里无所谓,可以放在根目录下,也可以放在 build 目录中)。这是一个 webpack 的配置文件,配合使用 vue-server-renderer 将我们的 skeleton.vue 文件内容构建为单个的 json 格式的文件(这是 Vue SSR 渲染的策略)

// webpack.skeleton.conf.js
'use strict'
const path = require('path')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')module.exports = {target: 'node',devtool: '#source-map',entry: './src/skeleton/skeleton.entry.js',output: {path: path.resolve(__dirname, '../dist'),publicPath: '/dist/',filename: '[name].js',libraryTarget: 'commonjs2'},module: {noParse: /es6-promise\.js$/,  // avoid webpack shimming processrules: [{test: /\.vue$/,loader: 'vue-loader',options: {compilerOptions: {preserveWhitespace: false}}},{test: /\.css$/,use: ['vue-style-loader', 'css-loader']}]},performance: {hints: false},externals: nodeExternals({// do not externalize CSS files in case we need to import it from a depwhitelist: /\.css$/}),plugins: [// 这是将服务器的整个输出构建为单个 JSON 文件的插件。// 默认文件名为 `vue-ssr-server-bundle.json`new VueSSRServerPlugin({filename: 'skeleton.json'})]
}

3、写完 skeleton.vue 的内容以后,使用 webpack-cli 运行这个 webpack.skeleton.conf.js 配置文件。

// package.json
"skeleton": "webpack --progress --config build/webpack.skeleton.conf.js"

然后运行:

npm i webpack-cli@3.3.10 -D
npm run skeleton

就会在 dist 文件夹中生成一个skeleton.json 文件。

4、将 skeleton.json 内容插入到模版文件 index.html 中。(在根目录下创建一个 skeleton.js 文件)

// skeleton.js
const fs = require('fs')
const { resolve } = require('path')
const { createBundleRenderer } = require('vue-server-renderer')function createRenderer(bundle, options) {return createBundleRenderer(bundle, Object.assign(options, {// recommended for performance// runInNewContext: false}))
}const handleError = err => {console.error(`error during render : ${req.url}`)console.error(err.stack)
}const bundle = require('./dist/skeleton.json')
const templatePath = resolve('./index.html')
const template = fs.readFileSync(templatePath, 'utf-8')
const renderer = createRenderer(bundle, {template
})// console.log(renderer)/*** 说明:* 默认的index.html中包含<%= BASE_URL %>的插值语法* 我们不在生成骨架屏这一步改变模板中的这个插值* 因为这个插值会在项目构建时完成* 但是如果模板中有这个插值语法,而我们在vue-server-renderder中使用这个模板,而不传值的话,是会报错的* 所以,我们去掉模板中的插值,而使用这个传参的方式,再将这两个插值原模原样返回到模板中* * 文档: https://cli.vuejs.org/zh/guide/html-and-static-assets.html#%E6%8F%92%E5%80%BC*/
const context = {title: '',  // default titlemeta: `<meta name="theme-color" content="#4285f4"><link rel="icon" href="<%= BASE_URL %>favicon.ico"><link rel="stylesheet" href="<%= BASE_URL %>css/reset.css">`
}renderer.renderToString(context, (err, html) => {if(err) {return handleError(err)}fs.writeFileSync(resolve(__dirname, './index.html'), html, 'utf-8')
})

5、模版 index.html 加上插槽注解
这里需要注意的是:index.html 中的 div#app 中要加一个注解插槽,<!--vue-ssr-outlet--> 这个是必须的,Vue SSR 文档中有说这个。这个注解是必须的,请注意!

<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>vue-for-test</title></head><body><div id="app"><!--vue-ssr-outlet--></div><!-- built files will be auto injected --></body>
</html>

参考连接:https://ssr.vuejs.org/zh/guide/#%E4%BD%BF%E7%94%A8%E4%B8%80%E4%B8%AA%E9%A1%B5%E9%9D%A2%E6%A8%A1%E6%9D%BF

6、执行

node skeleton.js

执行成功后,模版 index.html 中的 div#app 中的内容就会变成我们的骨架屏代码;

7、看一下效果
在这里插入图片描述
这个骨架屏,你觉得效果如何?

线上可以看到效果的例子也是有的: map-chart;记得选择,浏览器 -> network -> slow 3G 模式来预览 骨架屏效果。

在方案三中,还涉及到了 Vue SSR 的内容,关于 SSR 的知识的学习,可以参考我之前写的一个教程: https://github.com/Neveryu/vue-ssr-lessons

方案四、自动生成并自动插入静态骨架屏

饿了么开源的插件 page-skeleton-webpack-plugin ,它根据项目中不同的路由页面生成相应的骨架屏页面,并将骨架屏页面通过 webpack 打包到对应的静态路由页面中,不过要注意的是这个插件目前只支持 history 方式的路由,不支持 hash 方式,且目前只支持首页的骨架屏,并没有组件级的局部骨架屏实现,作者说以后会有计划实现(issue9)。

另外还有个插件 vue-skeleton-webpack-plugin,它将插入骨架屏的方式由手动改为自动,原理在构建时使用 Vue 预渲染功能,将骨架屏组件的渲染结果 HTML 片段插入 HTML 页面模版的挂载点中,将样式内联到 head 标签中。这个插件可以给单页面的不同路由设置不同的骨架屏,也可以给多页面设置,同时为了开发时调试方便,会将骨架屏作为路由写入 router 中,可谓是相当体贴了。

---------------------------(正文完)------------------------------------
一个前端的学习交流群,想进来面基的,可以点击这个logo ➹Vue学习交流,或者手动search群号:685486827,或者 qq 扫一扫

Vue学习交流


写在最后: 约定优于配置-------软件开发的简约原则.
-------------------------------- (完)--------------------------------------

我的:
个人网站: https://neveryu.github.io/neveryu/
Github: https://github.com/Neveryu
新浪微博: https://weibo.com/Neveryu

更多学习资源请关注我的新浪微博…


http://chatgpt.dhexx.cn/article/7SXoDRVy.shtml

相关文章

正确使用uniapp搭配微信开发者工具自带的骨架屏功能,生成骨架屏

重点&#xff1a;把index.skeleton.wxml和index.skeleton.wxss文件中的&#xff08;is““和data-event-opts””&#xff09;的整个属性删掉 一、描述&#xff1a;解决使用uniapp开发微信小程序生成骨架屏 很多人都知道微信开发者工具自带生成骨架屏的功能&#xff0c;但是却不…

vue骨架屏介绍

骨架屏可以理解为是当数据还未加载进来前&#xff0c;页面的一个空白版本&#xff0c;一个简单的关键渲染路径。可以看一下下面Facebook的骨架屏实现&#xff0c;可以看到在页面完全渲染完成之前&#xff0c;用户会看到一个样式简单&#xff0c;描绘了当前页面的大致框架的骨架…

微信小程序:骨架屏的实现方法

骨架屏是为了展示一个页面骨架而不含有实际的页面内容&#xff0c;从渲染效率上来讲&#xff0c;骨架屏它并不能使首屏渲染加快。由于骨架屏的一些使用又向用户渲染了额外的一些内容&#xff0c;这些内容是额外添加的、本来是不需要渲染的&#xff0c;它反而从整体上加长了首屏…

客户端骨架屏详解

一直以来&#xff0c;无论是Web还是iOS、Android的应用中&#xff0c;为了提升应用的加载等待这段时间的用户感知体验&#xff0c;各种技术层出不穷。其中&#xff0c;尤以菊花图以及由它衍生各种加载动画最为突出。 对于菊花图我们自不必多说&#xff0c;现在对于加载的设计体…

微信小程序使用骨架屏

骨架屏的使用越来越广泛。在微信小程序中使用骨架屏如果自己实现&#xff0c;不同的页面对应不同的骨架屏&#xff0c;会有一定难度&#xff1b;不过&#xff0c;微信小程序已经提供生成骨架屏功能&#xff0c;使得我们在开发中非常方便&#xff0c;下面介绍如何生成 在生成骨架…

Skeleton Screen — 骨架屏

用户体验一直是前端开发需要考虑的重要部分&#xff0c;在数据请求时常见到锁屏的loading动画&#xff0c;而现在越来越多的产品倾向于使用Skeleton Screen Loading(骨架屏)替代&#xff0c;以优化用户体验。 一种自动生成网页骨架屏的方式 前端骨架屏方案小结 Skeleton Scree…

element-骨架屏

使用场景&#xff1a;在需要等待加载内容的位置设置骨架屏。 主要代码&#xff1a;&#xff08;其中loading控制骨架屏的显示不显示&#xff0c;为false时不显示&#xff0c;为true时显示&#xff09; <template><div v-show"!loading"><!-- 第一行…

浅谈前端骨架屏方案

在图片与前端体验优化中&#xff0c;最重要的莫过于「骨架屏」了&#xff0c;因为它和“首屏体验”息息相关。 目前来说骨架屏基本上有两种方式&#xff1a; HTML CSS&#xff1a;主流。基本是自己在项目中以侵入式方式围绕html“定制”&#xff1b;微信小程序的骨架屏生成方…

前端骨架屏应用

什么是骨架屏 骨架屏可以理解为在页面数据尚未返回或页面未完成完全渲染前&#xff0c;先给用户呈现一个由灰白块组成的当前页面大致结构&#xff0c;让用户产生页面正在逐渐渲染的感受&#xff0c;从而使加载过程从视觉上变得流畅。 生成后的骨架屏页面如下图所示&#xff1…

如何实现骨架屏效果?

今天我们来用原生js实现一个骨架屏的效果&#xff0c;效果如下&#xff1a; 首先思考如何实现 思考实现方式 骨架屏的原理是在数据没加载出来的时候&#xff0c;使用滚动的背景颜色去替代&#xff0c;等到加载完毕后则显示对应内容 那么我们的核心就是实现一个.skeleton的样…

啥是骨架屏

&#xff08;一&#xff09;什么是骨架屏 骨架屏可以理解为是当数据还未加载进来前&#xff0c;页面的一个空白版本。在页面完全渲染完成之前&#xff0c;用户会看到一个样式简单&#xff0c;描绘了当前页面的大致框架的页面&#xff0c;然后骨架屏中各个占位部分被实际资源完…

前端骨架屏方案与实践

对于依赖接口渲染的页面&#xff0c;在拿到数据之前页面往往是空白的&#xff0c;为了提示用户当前正在加载中&#xff0c;往往会使用进度条、loading图标或骨架屏的方式。 对于前两种方案而言&#xff0c;实现比较简单&#xff1b;本文主要研究骨架屏的实现方案。 骨架屏(Ske…

网页骨架屏自动生成方案(dps)

来源&#xff1a;花满楼 https://zhuanlan.zhihu.com/p/74403911 什么是骨架屏&#xff1f; 什么是骨架屏呢&#xff1f;骨架屏(Skeleton Screen)是指在页面数据加载完成前&#xff0c;先给用户展示出页面的大致结构&#xff08;灰色占位图&#xff09;&#xff0c;在拿到接口数…

骨架屏

&#xff08;一&#xff09;什么是骨架屏 骨架屏可以理解为是当数据还未加载进来前&#xff0c;页面的一个空白版本。在页面完全渲染完成之前&#xff0c;用户会看到一个样式简单&#xff0c;描绘了当前页面的大致框架的页面&#xff0c;然后骨架屏中各个占位部分被实际资源完…

Vue中实现骨架屏的多种方式

vue-cli项目首页加载缓慢想要使用骨架屏效果&#xff0c;经过几天的实践&#xff0c;这里学习并记录一下vue项目自动生成骨架屏方法。 前言&#xff1a;骨架屏的作用主要是在网络请求较慢时&#xff0c;提供基础占位&#xff0c;当数据加载完成&#xff0c;恢复数据展示。这样给…

骨架屏原理——面试别再被挨打了

目录 前言 骨架屏是什么 骨架屏原理 用途&#xff1a; &#xff08;一&#xff09;简单实现 &#xff08;二&#xff09; vue项目中的构建 &#xff08;三&#xff09;自动化方案 前言 同样是之前练手项目中的&#xff0c;emmm,知道干嘛用的&#xff0c;没了解过具体原理…

性能测试总结之内存泄露和内存溢出

刚刚做完了一个项目的性能测试&#xff0c;“有幸”也遇到了内存泄露的案例&#xff0c;所以在此和大家分享一下。 主要从以下几部分来说明&#xff0c;关于内存和内存泄露、溢出的概念&#xff0c;区分内存泄露和内存溢出&#xff1b;内存的区域划分&#xff0c;了解GC回收机…

内存泄露与内存溢出的区别及解决方法

内存溢出与泄露的区别 内存溢出 out of memory&#xff0c;是指程序在申请内存时&#xff0c;没有足够的内存空间供其使用&#xff0c;出现out of memory&#xff1b;比如申请了一个integer,但给它存了long才能存下的数&#xff0c;那就是内存溢出。 内存泄露 memory leak&…

jvm故障 内存泄露和内存溢出总结

目录 内存泄漏memory leak 内存泄漏的分类&#xff08;按发生方式来分类&#xff09; 内存泄露的场景 静态集合类 / 长生命周期的对象持有短生命周期对象的引用 / 单例模式 /类加载器 各种连接&#xff0c;如数据库连接、网络连接和IO连接等 变量不合理的作用域 内部类持…

JVM——内存泄漏与内存溢出

内存泄漏与内存溢出 1. 面试题 什么是内存泄漏和什么是内存溢出 (陌陌) Java存在内存泄漏吗&#xff0c;内存泄漏的场景有哪些&#xff0c;如何避免(百度) Java 中会存在内存泄漏吗&#xff0c;简述一下&#xff1f;(猎聘) 内存泄漏是怎么造成的&#xff1f;(拼多多、字节跳动)…