領導需求骨架屏,我等屌絲員工只能上了,調研試用了各類方案,記錄一下坑與收穫。css
咱們的項目使用的是vant,試用了一把vant自帶的骨架屏,與領導需求不符,放棄。html
page-skeleton-webpack-pluginvue
安裝webpack
npm install --save-dev page-skeleton-webpack-plugin
npm install --save-dev html-webpack-plugin
複製代碼
vue.config.jsgit
const { SkeletonPlugin } = require("page-skeleton-webpack-plugin");
const path = require("path");
...
configureWebpack: config => {
...
config.plugins = [
// 使用骨架屏插件
new SkeletonPlugin({
pathname: path.resolve(__dirname, "./shell"), // 用來存儲 shell 文件的地址
staticDir: path.resolve(__dirname, "./dist"), // 最好和 `output.path` 相同
routes: ["/"] // 將須要生成骨架屏的路由添加到數組中
})
];
},
chainWebpack: config => {
if (isProduction) {
// 解決vue-cli3腳手架建立的項目壓縮html 幹掉<!-- shell -->致使骨架屏不生效
config.plugin("html").tap(opts => {
opts[0].minify.removeComments = false;
return opts;
});
}
}
複製代碼
進入項目根目錄github
cd /project-a
mkdir shell
複製代碼
index.htmlweb
<!--添加shell-->
<div id="app"><!-- shell --></div>
複製代碼
從新啓動,報錯vue-cli
這是由於使用page-skeleton-webpack-plugin
以前須要預加載html-webpack-plugin
,上面的vue.config.js
寫法可能致使html-webpack-plugin
沒有在骨架屏插件前面加載成功,改變寫法:shell
vue.config.jsnpm
...
configureWebpack: {
externals: {
vue: "Vue"
},
plugins: [
new SkeletonPlugin({
pathname: path.resolve(__dirname, "./shell"), // 用來存儲 shell 文件的地址
staticDir: path.resolve(__dirname, "./dist"), // 最好和 `output.path` 相同
routes: ["/"] // 將須要生成骨架屏的路由添加到數組中
})
]
},
...
複製代碼
從新啓動,成功
報錯沒有這樣路徑的文件,因爲衆所周知的緣由我沒法使用history方式的路由(餓了麼方案必須使用history的方式),加上此方案只能首屏使用,再三考慮,放棄了使用此方案!
這個方案使用下來和下面的vue-skeleton-webpack-plugin感受差很少,感受vue-skeleton-webpack-plugin稍微智能一點,此方案放棄
安裝
npm install vue-skeleton-webpack-plugin
複製代碼
vue.config.js
configureWebpack: config => {
config.plugins = [
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, "./src/skeleton.js")
}
},
minimize: true,
quiet: true
})
];
},
複製代碼
在src下新建js和vue模板
cd src
mkdir skeleton.js
vim skeleton.vue
複製代碼
skeleton.js
import Vue from "vue";
import Skeleton from "./Skeleton.vue";
export default new Vue({
components: {
Skeleton
},
render: h => h(Skeleton)
});
複製代碼
skeleton.vue
<template>
<div class="skeleton-wrapper">
<section class="skeleton-block">
<!-- eslint-disable vue/max-len -->
<img
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="
/>
<img
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTA4MCAyNjEiPjxkZWZzPjxwYXRoIGlkPSJiIiBkPSJNMCAwaDEwODB2MjYwSDB6Ii8+PGZpbHRlciBpZD0iYSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgeD0iLTUwJSIgeT0iLTUwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94Ij48ZmVPZmZzZXQgZHk9Ii0xIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggaW49InNoYWRvd09mZnNldE91dGVyMSIgdmFsdWVzPSIwIDAgMCAwIDAuOTMzMzMzMzMzIDAgMCAwIDAgMC45MzMzMzMzMzMgMCAwIDAgMCAwLjkzMzMzMzMzMyAwIDAgMCAxIDAiLz48L2ZpbHRlcj48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDEpIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCA0NGg1MzN2NDZIMjMweiIvPjxyZWN0IHdpZHRoPSIxNzIiIGhlaWdodD0iMTcyIiB4PSIzMCIgeT0iNDQiIGZpbGw9IiNGNkY2RjYiIHJ4PSI0Ii8+PHBhdGggZmlsbD0iI0Y2RjZGNiIgZD0iTTIzMCAxMThoMzY5djMwSDIzMHpNMjMwIDE4MmgzMjN2MzBIMjMwek04MTIgMTE1aDIzOHYzOUg4MTJ6TTgwOCAxODRoMjQydjMwSDgwOHpNOTE3IDQ4aDEzM3YzN0g5MTd6Ii8+PC9nPjwvc3ZnPg=="
/>
</section>
</div>
</template>
<script>
export default {
name: "Skeleton"
};
</script>
<style scoped>
.skeleton-block {
display: flex;
flex-direction: column;
padding: 16px;
}
</style>
複製代碼
從新啓動,報錯:
vue、vue-server-renderer版本不匹配,執行命令更新npm包
npm update
複製代碼
再次從新啓動,報錯:
此問題,和上面碰見的如出一轍,只是提示的方式不一樣而已,修改vue.config.js
configureWebpack: {
...
plugins: [
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, "./src/skeleton.js")
}
},
minimize: true,
quiet: true
})
]
},
複製代碼
從新啓動,ok,骨架屏已經出來了
不是我想要的效果,修改skeleton.vue
和vue.config.js
skeleton.vue
<template>
<div class="skeleton">
<div class="skeleton-head">
<div class="head-item"></div>
<div class="head-item"></div>
<div class="head-item"></div>
</div>
<div class="skeleton-content"></div>
<div class="skeleton-content"></div>
</div>
</template>
<script>
export default {
name: "skeleton"
};
</script>
<style scoped>
.skeleton {
padding: 10px;
}
.skeleton-head {
width: 100%;
display: flex;
justify-content: space-between;
}
.head-item {
width: 30%;
height: 50px;
}
.skeleton-content {
width: 100%;
height: 200px;
margin-top: 20px;
border-radius: 10px;
}
.skeleton .head-item,
.skeleton .skeleton-content {
background: rgb(194, 207, 214);
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0.15) 25%,
transparent 25%
);
background-size: 20rem 20rem;
animation: skeleton-stripes 1s linear infinite;
}
@keyframes skeleton-stripes {
from {
background-position: 0 0;
}
to {
background-position: 20rem 0;
}
}
</style>
複製代碼
vue.config.js
css: {
// 開啓CSS樣式分離,開發環境下,默認爲false,extract默認爲false的時候,vue-skeleton-webpack-plugin自定義樣式不生效,一片空白的
extract: true,
...
},
複製代碼
如今這樣的是,全部頁面統一使用一個骨架屏,很差,仍是改爲單獨每一個頁面使用單獨的骨架屏吧!
src下新建文件夾skeleton
cd src
mkdir skeleton
// 移動骨架屏文件到skeleton文件夾下
mv skeleton.vue ./skeleton
複製代碼
修改 skeleton.js
import Vue from "vue";
import skeletonHome from "./skeleton/Skeleton.vue";
export default new Vue({
components: {
skeletonHome
},
template: `
<div>
<skeletonHome id="skeleton-home" style="display:none"/>
</div>
`
});
複製代碼
修改vue.config.js
configureWebpack: {
...
plugins: [
// vue-skeleton-webpack-plugin 骨架屏
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: path.join(__dirname, "./src/skeleton.js")
}
},
minimize: true,
quiet: true,
// 根據路由顯示骨架屏
router: {
mode: "hash",
routes: [
{
path: "/",
skeletonId: "skeleton-home"
}
]
}
})
]
},
複製代碼
從新啓動,ok
到這裏就告一段落了,若是哪一個頁面須要有骨架屏,就在
skeleton
文件夾下新建一個.vue文件,在skeleton.js
中引入,在vue.config.js
中添加對應的路由便可
原本想弄一個徹底自動的骨架屏方案,根據每個頁面自動生成一個骨架屏,可是我本人太菜了,暫時對此功能無能爲力。市面上的方案就徹底沒有一個能全自動的,餓了麼說是計劃弄一個,遙遙無期;淘寶骨架屏方案,搜索了一下,只是有一些文章介紹,貌似木有開源;騰訊搜索更多的是小程序骨架屏方案;京東貌似有一個dps方案,我去看了下他們的git,講的挺好,可是demo沒有實際參考的意義,有不少疑問,並且仍是新出,本人不是勇士,仍是等等吧!
給項目加一個骨架屏吧
基於vue-cli實現自動生成Skeleton Page,多頁skeleton
基於 vue-skeleton-webpack-plugin 的骨架屏實戰