vue項目中使用骨架屏的方法
現(xiàn)在的應用開發(fā),基本上都是前后端分離的,前端主流框架有SPA、MPA等,那么解決頁面渲染、白屏時間成為首要關注的點
webpack可以按需加載,減小首屏需要加載代碼的體積;
使用CDN技術、靜態(tài)代碼等緩存技術,可以減小加載渲染的時長
問題:但是首頁依然存在加載、渲染等待時長的問題。那么如何從視覺效果上減小首屏白屏的時間呢?
骨架屏:舉個例子:其實就是在模版文件中id=app容器下面寫想要展示的效果,在new Vue(option)之后,該id下的內容就被替換了( 這時候,可能Vue編譯生成的內容還沒有掛載。因為new Vue的時候會進行一系列的初始化,這也需要耗費時間的)。這樣就可以從視覺上減小白屏的時間
骨架屏的實現(xiàn)方式
1、直接在模版文件id=app容器下面,寫進想要展示的效果html
2、直接在模板文件id=app容器下面,用圖片展示
3、使用vue ssr提供的webpack插件
4、自動生成并且自動插入靜態(tài)骨架屏
方式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文件夾,在該目錄下創(chuàng)建文件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(首頁骨架屏展示效果的代碼)
<template> <div class="skeleton-home"> <div>加載中...</div> </div> </template> <style> .skeleton-home { width: 100vw; height: 100vh; background-color: #eaeaea; } </style>
App.vue(根組件)
<template> <div id="app"> <!-- 根組件 --> <home style="display:none" id="homeSkeleton"></home> </div> </template> <script> import home from './home.skeleton.vue' export default{ components: { home } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } *{ padding: 0; margin: 0; } </style>
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)處理動態(tài)導入(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中實現(xiàn)骨架屏:http://www.360doc.com/content/20/0709/11/21412_923150401.shtml
Vue ssr渲染踩過的坑:https://blog.csdn.net/chen801090/article/details/105974987/
到此這篇關于vue項目中使用骨架屏的方法的文章就介紹到這了,更多相關vue 骨架屏內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
VUE-Table上綁定Input通過render實現(xiàn)雙向綁定數(shù)據的示例
今天小編就為大家分享一篇VUE-Table上綁定Input通過render實現(xiàn)雙向綁定數(shù)據的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08