在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(首頁骨架屏展示效果的程式碼)
<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)處理動態匯入(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
},
//
//
// 外接化應用程式依賴模組。可以使伺服器構建速度更快,
// 並生成較小的 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了
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69997029/viewspace-2773552/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Vue專案骨架屏注入實踐Vue
- VUE單頁應用骨架屏方案Vue
- Vue 頁面骨架屏注入實踐Vue
- Vue頁面骨架屏注入實踐Vue
- 骨架屏(Skeleton Screen)在Android中的應用Android
- 在vue專案中優雅的使用SvgVueSVG
- bing Map 在vue專案中的使用Vue
- react骨架屏React
- 在vue專案中使用elementUIVueUI
- 在vue專案中mock資料VueMock
- 使用Maven命令列快速建立專案骨架(archetype)Maven命令列
- vue.js 實踐總結(三)Skeleton 骨架屏渲染Vue.js
- 小程式之骨架屏
- Flutter 實現骨架屏Flutter
- 在 Laradock 中開發 Vue 專案Vue
- Vue專案中新增鎖屏功能Vue
- 在vue-cli專案中使用echartsVueEcharts
- 在Vue專案中使用Echarts(三): Echarts中的其他常用圖VueEcharts
- 使用CSS自定義屬性構建骨架屏CSS
- vue-ssr在專案中的實踐Vue
- 前端骨架屏方案小結前端
- 在Vue專案中使用snapshot測試Vue
- Flow靜態型別檢查及在Vue專案中的使用型別Vue
- vue專案中如何使用this.$confirmVue
- Android 提升使用者體驗之骨架屏Android
- 在專案中如何直接使用hystrix?
- 在Vue專案裡面使用d3.jsVueJS
- 【神器】視覺化建立骨架屏視覺化
- 客戶端骨架屏實現客戶端
- 在vue專案中自定義事件匯流排eventHubVue事件
- 在 React 專案中全量使用 HooksReactHook
- JWT 在專案中的實際使用JWT
- maven使用mvn archetype:generate命令建立專案骨架遇到的問題Maven
- 在vue專案中 使用driver.js來進行頁面分步引導VueJS
- 在Vue專案中使用npm安裝bootstrap以及jqueryVueNPMbootjQuery
- 使用vue-cli搭建VUE專案Vue
- 小程式骨架屏動態注入元件元件
- 骨架屏(page-skeleton-webpack-plugin)初探WebPlugin