热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue项目中使用骨架屏的方法_vue.js

在页面加载数据之前,有一段空白时间,要么用loading加载,要么就用骨架屏,本文主要介绍了vue项目中使用骨架屏的方法,

现在的应用开发,基本上都是前后端分离的,前端主流框架有SPA、MPA等,那么解决页面渲染、白屏时间成为首要关注的点

webpack可以按需加载,减小首屏需要加载代码的体积;

使用CDN技术、静态代码等缓存技术,可以减小加载渲染的时长

问题:但是首页依然存在加载、渲染等待时长的问题。那么如何从视觉效果上减小首屏白屏的时间呢?

骨架屏:举个例子:其实就是在模版文件中id=app容器下面写想要展示的效果,在new Vue(option)之后,该id下的内容就被替换了( 这时候,可能Vue编译生成的内容还没有挂载。因为new Vue的时候会进行一系列的初始化,这也需要耗费时间的)。这样就可以从视觉上减小白屏的时间

骨架屏的实现方式

1、直接在模版文件id=app容器下面,写进想要展示的效果html

2、直接在模板文件id=app容器下面,用图片展示

3、使用vue ssr提供的webpack插件

4、自动生成并且自动插入静态骨架屏

方式1和方式2存在的缺陷:针对不同入口,展示的效果都一样,导致不能灵活的针对不同的入口,展示不同的样式

方式3可以针对不同的入口展示不同的效果。(实质也是先通过ssr生成一个json文件,然后将json文件内容注入到模板文件的id=app容器下)

方案一、直接在模版文件id=app容器下面,写进想要展示的效果html

在根目录的模版文件内写进内容,如红色圈出来的地方

在浏览器打开项目

在调用new Vue之前的展示效果(只是做了个简单效果,不喜勿喷):

可以看到elements中id=app的容器下内容,就是我们写进的骨架屏效果内容

在看下调了new Vue之后的效果,id=app容器下的内容被vue编译生成的内容替换了

方案二、直接在模板文件id=app容器下面,用图片展示(这个就不做展示了)

方案三、使用vue ssr提供的webpack插件:即用.vue文件完成骨架屏

在方案一的基础上,将骨架屏的代码抽离出来,不在模版文件里面书写代码,而是在vue文件里面书写效果代码,这样便于维护

1、在根目录下建一个skeleton文件夹,在该目录下创建文件App.vue文件(根组件,类似Vue项目的App.vue)、home.skeleton.vue(首页骨架屏展示效果的代码,类似Vue项目写的路由页面)、skeleton-entry.js(入口文件类似Vue项目的入口文件)、plugin/server-plugin.js(vue-server-renderer包提供了server-plugin插件,从里面将代码拷贝出来)

home.skeleton.vue(首页骨架屏展示效果的代码)


 

App.vue(根组件)



skeleton-entry.js(入口文件)

// 入口文件
import Vue from 'vue'
import App from './App.vue'
let skeleton = new Vue({
  render(h) {
    return h(App)
  }
})
export default skeleton

plugin/server-plugin.js(vue-server-renderer包提供了server-plugin插件)

'use strict';
 
/*  */
 
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
 
var ref = require('chalk');
var red = ref.red;
var yellow = ref.yellow;
 
var prefix = "[vue-server-renderer-webpack-plugin]";
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };
 
var validate = function (compiler) {
  if (compiler.options.target !== 'node') {
    warn('webpack config `target` should be "node".');
  }
 
  if (compiler.options.output && compiler.options.output.libraryTarget !== 'commonjs2') {
    warn('webpack config `output.libraryTarget` should be "commonjs2".');
  }
 
  if (!compiler.options.externals) {
    tip(
      'It is recommended to externalize dependencies in the server build for ' +
      'better build performance.'
    );
  }
};
 
var VueSSRServerPlugin = function VueSSRServerPlugin (options) {
  if ( optiOns=== void 0 ) optiOns= {};
 
  this.optiOns= Object.assign({
    filename: 'vue-ssr-server-bundle.json'
  }, options);
};
 
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
    var this$1 = this;
 
  validate(compiler);
 
  compiler.plugin('emit', function (compilation, cb) {
    var stats = compilation.getStats().toJson();
    var entryName = Object.keys(stats.entrypoints)[0];
    var entryAssets = stats.entrypoints[entryName].assets.filter(isJS);
 
    if (entryAssets.length > 1) {
      throw new Error(
        "Server-side bundle should have one single entry file. " +
        "Avoid using CommonsChunkPlugin in the server config."
      )
    }
 
    var entry = entryAssets[0];
    if (!entry || typeof entry !== 'string') {
      throw new Error(
        ("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?")
      )
    }
 
    var bundle = {
      entry: entry,
      files: {},
      maps: {}
    };
 
    stats.assets.forEach(function (asset) {
      if (asset.name.match(/\.js$/)) {
        bundle.files[asset.name] = compilation.assets[asset.name].source();
      } else if (asset.name.match(/\.js\.map$/)) {
        bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source());
      }
      // do not emit anything else for server
      delete compilation.assets[asset.name];
    });
 
    var json = JSON.stringify(bundle, null, 2);
    var filename = this$1.options.filename;
 
    compilation.assets[filename] = {
      source: function () { return json; },
      size: function () { return json.length; }
    };
 
    cb();
  });
};
 
module.exports = VueSSRServerPlugin;

2、新建一个骨架屏构建配置文件:build/webpack.skeleton.conf.js,这个文件配合vue-server-renderer插件,将App.vue内容构建成单个json格式的文件

'use strict'
 
const path = require('path')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('../skeleton/plugin/server-plugin')
 
module.exports = {
  // 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),
  // 并且还会在编译 Vue 组件时,
  // 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。
  target: 'node',
 
  // 对 bundle renderer 提供 source map 支持
  devtool: 'source-map',
 
  // 将 entry 指向应用程序的 server entry 文件
  entry: path.resolve(__dirname, '../skeleton/skeleton-entry.js'),
 
  output: {
    path: path.resolve(__dirname, '../skeleton'),  // 生成的文件的目录
    publicPath: '/skeleton/',
    filename: '[name].js',
    libraryTarget: 'commonjs2' // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
  },
 
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            preserveWhitespace: false
          }
        }
      },
      {
        test: /\.css$/,
        use: ['vue-style-loader', 'css-loader']
      }
    ]
  },
 
  performance: {
    hints: false
  },
 
  // https://webpack.js.org/configuration/externals/#function
  // https://github.com/liady/webpack-node-externals
  // 外置化应用程序依赖模块。可以使服务器构建速度更快,
  // 并生成较小的 bundle 文件。
  externals: nodeExternals({
    // 不要外置化 webpack 需要处理的依赖模块。
    // 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,
    // 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单
    allowlist: /\.css$/
  }),
 
  // 这是将服务器的整个输出
  // 构建为单个 JSON 文件的插件。
  // 不配置filename,则默认文件名为 `vue-ssr-server-bundle.json`
  plugins: [
    new VueSSRServerPlugin({
      filename: 'skeleton.json'
    })
  ]
}

3、使用webpack-cli运行文件webpack.skeleton.conf.js,生成skeleton.json文件,放置在文件夹skeleton下

在package.json文件里面书写运行命令:create-skeleton

  "scripts": {
    "create-skeleton": "webpack --progress --config build/webpack.skeleton.conf.js",
    "fill-skeleton": "node ./skeleton/skeleton.js"
  }

在控制台上运行命令:

npm run create-skeleton

文件夹skeleton下就会多出skelleton.json文件

4、将生成的skeleton.json内容注入到根目录下的index.html(模版文件)

1)在文件夹skeleton下新建skeleton.js

// 将生成的skeleton.json的内容填充到模板文件中
const fs = require('fs')
const { resolve } = require('path')
const createBundleRenderer = require('vue-server-renderer').createBundleRenderer
 
// 读取skeleton.json,以skeleton/index.html为模版写入内容
const renderer = createBundleRenderer(resolve(__dirname, '../skeleton/skeleton.json'), {
  template: fs.readFileSync(resolve(__dirname, '../skeleton/index.html'), 'utf-8')
})
// 把上一步模版完成的内容写入根目录下的模版文件'index.html'
renderer.renderToString({}, (err, html) => {
  if (err) {
    return console.log(err)
  }
  console.log('render complete!')
  fs.writeFileSync('index.html', html, 'utf-8')
})

2)添加运行命令:fill-skeleton

"fill-skeleton": "node ./skeleton/skeleton.js"

3)在控制台上运行该命令,则skeleton.json文件内容被填充至根目录下的模板文件index.html了

参考文章:

利用Vue SSR 做骨架屏注入:https://www.cnblogs.com/goloving/p/11397371.html

在Vue中实现骨架屏:http://www.360doc.com/content/20/0709/11/21412_923150401.shtml

Vue ssr渲染踩过的坑:https://blog.csdn.net/chen801090/article/details/105974987/


推荐阅读
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 在腾讯云服务器上部署Nginx的详细指南中,首先需要确保安装必要的依赖包。如果这些依赖包已安装,可直接跳过此步骤。具体命令包括 `yum -y install gcc gcc-c++ wget net-tools pcre-devel zlib-devel`。接下来,本文将详细介绍如何下载、编译和配置Nginx,以确保其在腾讯云服务器上顺利运行。此外,还将提供一些优化建议,帮助用户提升Nginx的性能和安全性。 ... [详细]
  • 在今天的实践中,我深入学习了网页图像抓取技术,通过编写爬虫程序批量获取网站上的图片资源。具体来说,我选择了一个包含大量高质量图片的网站作为练习对象,并成功实现了将这些图片批量下载到本地存储。这一过程不仅提升了我对爬虫技术的理解,还增强了我的编程能力。 ... [详细]
  • 可转债数据智能抓取与分析平台优化
    本项目旨在优化可转债数据的智能抓取与分析平台。通过爬取集思录上的可转债信息(排除已发布赎回的债券),并结合安道全教授提出的三条安全线投资策略,新增了建仓线、加仓线和重仓线,以提供更精准的投资建议。 ... [详细]
  • 为了深入了解某些测试框架的工作原理,并在培训中构建一个简单的测试框架,我系统地研究了 should.js 的源代码。本文将分享我的学习过程和分析结果,帮助读者更好地掌握 should.js 的核心机制。 ... [详细]
  • XAMPP 遇到 404 错误:无法找到请求的对象
    在使用 XAMPP 时遇到 404 错误,表示请求的对象未找到。通过详细分析发现,该问题可能由以下原因引起:1. `httpd-vhosts.conf` 文件中的配置路径错误;2. `public` 目录下缺少 `.htaccess` 文件。建议检查并修正这些配置,以确保服务器能够正确识别和访问所需的文件路径。 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 如何在WAMP环境中更改默认的www根目录路径
    在WAMP环境中更改默认的www根目录路径,可以通过编辑Apache配置文件实现。具体步骤如下:打开D:\WampServer\bin\apache\apache2.2.22\conf\httpd.conf文件,找到并修改DocumentRoot和指令,将路径更改为新的根目录位置。保存文件后重启WAMP服务,即可生效。此方法适用于需要自定义项目部署路径的开发者。 ... [详细]
  • 本文深入探讨了 Git 与 SVN 的高效使用技巧,旨在帮助开发者轻松应对版本控制中的各种挑战。通过详细解析两种工具的核心功能与最佳实践,读者将能够更好地掌握版本管理的精髓,提高开发效率。 ... [详细]
  • PyQt5 QTextEdit:深入解析Python中多功能GUI库的应用与实现
    本文详细探讨了 PyQt5 中 QTextEdit 组件在 Python 多功能 GUI 库中的应用与实现。PyQt5 是 Qt 框架的 Python 绑定,提供了超过 620 个类和 6000 个函数及方法,广泛应用于跨平台应用程序开发。QTextEdit 作为其中的重要组件,支持丰富的文本编辑功能,如富文本格式、文本高亮和自定义样式等。PyQt5 的流行性不仅在于其强大的功能,还在于其易用性和灵活性,使其成为开发复杂用户界面的理想选择。 ... [详细]
author-avatar
四只猪1984
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有