提升首屏的加載速度,是前端性能優(yōu)化中最重要的環(huán)節(jié),這里筆者梳理出一些 常規(guī)且有效
的首屏優(yōu)化建議
目標(biāo):通過(guò)對(duì)比優(yōu)化前后的性能變化翠肘,來(lái)驗(yàn)證方案的有效性,了解并掌握其原理
1商佑、路由懶加載
SPA 項(xiàng)目锯茄,一個(gè)路由對(duì)應(yīng)一個(gè)頁(yè)面,如果不做處理茶没,項(xiàng)目打包后,會(huì)把所有頁(yè)面打包成一個(gè)文件晚碾,當(dāng)用戶打開首頁(yè)時(shí)抓半,會(huì)一次性加載所有的資源,造成首頁(yè)加載很慢格嘁,降低用戶體驗(yàn)笛求。
列一個(gè)實(shí)際項(xiàng)目的打包詳情:
將路由全部改成懶加載
// 通過(guò)webpackChunkName設(shè)置分割后代碼塊的名字
const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue");
const MetricGroup = () => import(/* webpackChunkName: "metricGroup" */ "@/views/metricGroup/index.vue");
…………
const routes = [
{
path: "/",
name: "home",
component: Home
},
{
path: "/metricGroup",
name: "metricGroup",
component: MetricGroup
},
…………
]
重新打包后,首頁(yè)資源拆分為 app.js 和 home.js糕簿,以及對(duì)應(yīng)的 css 文件
通過(guò)路由懶加載探入,該項(xiàng)目的首頁(yè)資源壓縮約 52%
路由懶加載的原理
懶加載前提的實(shí)現(xiàn):ES6的動(dòng)態(tài)地加載模塊——import()
調(diào)用 import() 之處,被作為分離的模塊起點(diǎn)懂诗,意思是蜂嗽,被請(qǐng)求的模塊和它引用的所有子模塊,會(huì)分離到一個(gè)單獨(dú)的 chunk 中
——摘自《webpack——模塊方法》的import()小節(jié)
要實(shí)現(xiàn)懶加載植旧,就得先將進(jìn)行懶加載的子模塊分離出來(lái)辱揭,打包成一個(gè)單獨(dú)的文件。
webpackChunkName 作用是 webpack 在打包的時(shí)候病附,對(duì)異步引入的庫(kù)代碼(lodash)進(jìn)行代碼分割時(shí)问窃,設(shè)置代碼塊的名字。webpack 會(huì)將任何一個(gè)異步模塊與相同的塊名稱組合到相同的異步塊中完沪。
2域庇、組件懶加載
除了路由的懶加載外,組件的懶加載在很多場(chǎng)景下也有重要的作用
舉個(gè)??:
home 頁(yè)面 和 about 頁(yè)面覆积,都引入了 dialogInfo 彈框組件较剃,該彈框不是一進(jìn)入頁(yè)面就加載,而是需要用戶手動(dòng)觸發(fā)后才展示出來(lái)
home 頁(yè)面示例:
<template>
<div class="homeView">
<p>home 頁(yè)面</p>
<el-button @click="dialogVisible = !dialogVisible">打開彈框</el-button>
<dialogInfo v-if="dialogVisible" />
</div>
</template>
<script>
import dialogInfo from '@/components/dialogInfo';
export default {
name: 'homeView',
components: {
dialogInfo
}
}
</script>
項(xiàng)目打包后技健,發(fā)現(xiàn) home.js 和 about.js 均包括了該彈框組件的代碼(在 dist 文件中搜索dialogInfo彈框組件)
當(dāng)用戶打開 home 頁(yè)時(shí)写穴,會(huì)一次性加載該頁(yè)面所有的資源,我們期望的是用戶觸發(fā)按鈕后雌贱,再加載該彈框組件的資源
這種場(chǎng)景下啊送,就很適合用懶加載的方式引入
彈框組件懶加載:
<script>
const dialogInfo = () => import(/* webpackChunkName: "dialogInfo" */ '@/components/dialogInfo');
export default {
name: 'homeView',
components: {
dialogInfo
}
}
</script>
重新打包后,home.js 和 about.js 中沒有了彈框組件的代碼欣孤,該組件被獨(dú)立打包成 dialogInfo.js馋没,當(dāng)用戶點(diǎn)擊按鈕時(shí),才會(huì)去加載 dialogInfo.js 和 dialogInfo.css
最終降传,使用組件路由懶后篷朵,該項(xiàng)目的首頁(yè)資源進(jìn)一步減少約 11%
組件懶加載的使用場(chǎng)景
有時(shí)資源拆分的過(guò)細(xì)也不好,可能會(huì)造成瀏覽器 http 請(qǐng)求的增多
總結(jié)出三種適合組件懶加載的場(chǎng)景:
1)該頁(yè)面的 JS 文件體積大婆排,導(dǎo)致頁(yè)面打開慢声旺,可以通過(guò)組件懶加載進(jìn)行資源拆分,利用瀏覽器并行下載資源段只,提升下載速度(比如首頁(yè))
2)該組件不是一進(jìn)入頁(yè)面就展示腮猖,需要一定條件下才觸發(fā)(比如彈框組件)
3)該組件復(fù)用性高,很多頁(yè)面都有引入赞枕,利用組件懶加載抽離出該組件澈缺,一方面可以很好利用緩存,同時(shí)也可以減少頁(yè)面的 JS 文件大锌簧簟(比如表格組件姐赡、圖形組件等)
3、合理使用 Tree shaking
Tree shaking 的作用:消除無(wú)用的 JS 代碼柠掂,減少代碼體積
舉個(gè)??:
// util.js
export function targetType(target) {
return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
}
export function deepClone(target) {
return JSON.parse(JSON.stringify(target));
}
項(xiàng)目中只使用了 targetType 方法项滑,但未使用 deepClone 方法,項(xiàng)目打包后陪踩,deepClone 方法不會(huì)被打包到項(xiàng)目里
tree-shaking 原理:
依賴于ES6的模塊特性杖们,ES6模塊依賴關(guān)系是確定的悉抵,和運(yùn)行時(shí)的狀態(tài)無(wú)關(guān),可以進(jìn)行可靠的靜態(tài)分析摘完,這就是 tree-shaking 的基礎(chǔ)
靜態(tài)分析就是不需要執(zhí)行代碼姥饰,就可以從字面量上對(duì)代碼進(jìn)行分析。ES6之前的模塊化孝治,比如 CommonJS 是動(dòng)態(tài)加載列粪,只有執(zhí)行后才知道引用的什么模塊,就不能通過(guò)靜態(tài)分析去做優(yōu)化谈飒,正是基于這個(gè)基礎(chǔ)上岂座,才使得 tree-shaking 成為可能
Tree shaking 并不是萬(wàn)能的
并不是說(shuō)所有無(wú)用的代碼都可以被消除,還是上面的代碼杭措,換個(gè)寫法 tree-shaking 就失效了
// util.js
export default {
targetType(target) {
return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
},
deepClone(target) {
return JSON.parse(JSON.stringify(target));
}
};
// 引入并使用
import util from '../util';
util.targetType(null)
同樣的费什,項(xiàng)目中只使用了 targetType 方法,未使用 deepClone 方法手素,項(xiàng)目打包后鸳址,deepClone 方法還是被打包到項(xiàng)目里
在 dist 文件中搜索 deepClone 方法
究其原因,export default 導(dǎo)出的是一個(gè)對(duì)象泉懦,無(wú)法通過(guò)靜態(tài)分析判斷出一個(gè)對(duì)象的哪些變量未被使用稿黍,所以 tree-shaking 只對(duì)使用 export 導(dǎo)出的變量生效
這也是函數(shù)式編程越來(lái)越火的原因,因?yàn)榭梢院芎美?tree-shaking 精簡(jiǎn)項(xiàng)目的體積崩哩,也是 vue3 全面擁抱了函數(shù)式編程的原因之一
4巡球、骨架屏優(yōu)化白屏?xí)r長(zhǎng)
使用骨架屏,可以縮短白屏?xí)r間邓嘹,提升用戶體驗(yàn)酣栈。
國(guó)內(nèi)大多數(shù)的主流網(wǎng)站都使用了骨架屏,特別是手機(jī)端的項(xiàng)目吴超。
SPA 單頁(yè)應(yīng)用钉嘹,無(wú)論 vue 還是 react,最初的 html 都是空白的鲸阻,需要通過(guò)加載 JS 將內(nèi)容掛載到根節(jié)點(diǎn)上,這套機(jī)制的副作用:會(huì)造成長(zhǎng)時(shí)間的白屏缨睡。
常見的骨架屏插件就是基于這種原理鸟悴,在項(xiàng)目打包時(shí)將骨架屏的內(nèi)容直接放到 html 文件的根節(jié)點(diǎn)中。
使用骨架屏插件奖年,打包后的 html 文件(根節(jié)點(diǎn)內(nèi)部為骨架屏):
同一項(xiàng)目细诸,對(duì)比使用骨架屏前后的 FP 白屏?xí)r間:
無(wú)骨架屏:白屏?xí)r間
1063ms
有骨架屏:白屏?xí)r間
144ms
骨架屏確實(shí)是優(yōu)化白屏的不二選擇,白屏?xí)r間縮短了 86%
骨架屏插件
這里以 vue-skeleton-webpack-plugin
插件為例陋守,該插件的亮點(diǎn)是可以給不同的頁(yè)面設(shè)置不同的骨架屏震贵,這點(diǎn)確實(shí)很酷
1)安裝
npm i vue-skeleton-webpack-plugin
2)vue.config.js 配置
// 骨架屏
const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin");
module.exports = {
configureWebpack: {
plugins: [
new SkeletonWebpackPlugin({
// 實(shí)例化插件對(duì)象
webpackConfig: {
entry: {
app: path.join(__dirname, './src/skeleton.js') // 引入骨架屏入口文件
}
},
minimize: true, // SPA 下是否需要壓縮注入 HTML 的 JS 代碼
quiet: true, // 在服務(wù)端渲染時(shí)是否需要輸出信息到控制臺(tái)
router: {
mode: 'hash', // 路由模式
routes: [
// 不同頁(yè)面可以配置不同骨架屏
// 對(duì)應(yīng)路徑所需要的骨架屏組件id利赋,id的定義在入口文件內(nèi)
{ path: /^\/home(?:\/)?/i, skeletonId: 'homeSkeleton' },
{ path: /^\/detail(?:\/)?/i, skeletonId: 'detailSkeleton' }
]
}
})
]
}
}
3)新建 skeleton.js 入口文件
// skeleton.js
import Vue from "vue";
// 引入對(duì)應(yīng)的骨架屏頁(yè)面
import homeSkeleton from "./views/homeSkeleton";
import detailSkeleton from "./views/detailSkeleton";
export default new Vue({
components: {
homeSkeleton,
detailSkeleton,
},
template: `
<div>
<homeSkeleton id="homeSkeleton" style="display:none;" />
<detailSkeleton id="detailSkeleton" style="display:none;" />
</div>
`,
});
5、長(zhǎng)列表虛擬滾動(dòng)
首頁(yè)中不乏有需要渲染長(zhǎng)列表的場(chǎng)景猩系,當(dāng)渲染條數(shù)過(guò)多時(shí)媚送,所需要的渲染時(shí)間會(huì)很長(zhǎng),滾動(dòng)時(shí)還會(huì)造成頁(yè)面卡頓寇甸,整體體驗(yàn)非常不好
虛擬滾動(dòng)——指的是只渲染可視區(qū)域的列表項(xiàng)塘偎,非可見區(qū)域的不渲染,在滾動(dòng)時(shí)動(dòng)態(tài)更新可視區(qū)域拿霉,該方案在優(yōu)化大量數(shù)據(jù)渲染時(shí)效果是很明顯的
虛擬滾動(dòng)圖例:
虛擬滾動(dòng)基本原理:
計(jì)算出 totalHeight 列表總高度吟秩,并在觸發(fā)時(shí)滾動(dòng)事件時(shí)根據(jù) scrollTop 值不斷更新 startIndex 以及 endIndex ,以此從列表數(shù)據(jù) listData 中截取對(duì)應(yīng)元素
虛擬滾動(dòng)性能對(duì)比:
使用虛擬滾動(dòng)使性能提升了 78%
虛擬滾動(dòng)插件
虛擬滾動(dòng)的插件有很多绽淘,比如 vue-virtual-scroller涵防、vue-virtual-scroll-list、react-tiny-virtual-list沪铭、react-virtualized 等
這里簡(jiǎn)單介紹 vue-virtual-scroller 的使用
// 安裝插件
npm install vue-virtual-scroller
// main.js
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
Vue.use(VueVirtualScroller)
// 使用
<template>
<RecycleScroller
class="scroller"
:items="list"
:item-size="32"
key-field="id"
v-slot="{ item }">
<div class="user"> {{ item.name }} </div>
</RecycleScroller>
</template>
該插件主要有 RecycleScroller.vue壮池、DynamicScroller.vue 這兩個(gè)組件,其中 RecycleScroller 需要 item 的高度為靜態(tài)的伦意,也就是列表每個(gè) item 的高度都是一致的火窒,而 DynamicScroller 可以兼容 item 的高度為動(dòng)態(tài)的情況
6狮暑、Web Worker 優(yōu)化長(zhǎng)任務(wù)
由于瀏覽器 GUI 渲染線程與 JS 引擎線程是互斥的關(guān)系聪全,當(dāng)頁(yè)面中有很多長(zhǎng)任務(wù)時(shí),會(huì)造成頁(yè)面 UI 阻塞孝凌,出現(xiàn)界面卡頓离钝、掉幀等情況
查看頁(yè)面的長(zhǎng)任務(wù):
打開控制臺(tái)票编,選擇 Performance 工具,點(diǎn)擊 Start 按鈕卵渴,展開 Main 選項(xiàng)慧域,會(huì)發(fā)現(xiàn)有很多紅色的三角,這些就屬于長(zhǎng)任務(wù)(長(zhǎng)任務(wù):執(zhí)行時(shí)間超過(guò)50ms的任務(wù))
測(cè)試實(shí)驗(yàn):
如果直接把下面這段代碼直接丟到主線程中浪读,計(jì)算過(guò)程中頁(yè)面一直處于卡死狀態(tài)昔榴,無(wú)法操作
let sum = 0;
for (let i = 0; i < 200000; i++) {
for (let i = 0; i < 10000; i++) {
sum += Math.random()
}
}
使用 Web Worker 執(zhí)行上述代碼時(shí),計(jì)算過(guò)程中頁(yè)面正车忾伲可操作互订、無(wú)卡頓
// worker.js
onmessage = function (e) {
// onmessage獲取傳入的初始值
let sum = e.data;
for (let i = 0; i < 200000; i++) {
for (let i = 0; i < 10000; i++) {
sum += Math.random()
}
}
// 將計(jì)算的結(jié)果傳遞出去
postMessage(sum);
}
Web Worker 具體的使用與案例,詳情見 一文徹底了解Web Worker痘拆,十萬(wàn)仰禽、百萬(wàn)條數(shù)據(jù)都是弟弟??
Web Worker 的通信時(shí)長(zhǎng)
并不是執(zhí)行時(shí)間超過(guò) 50ms 的任務(wù),就可以使用 Web Worker,還要先考慮通信時(shí)長(zhǎng)
的問(wèn)題
假如一個(gè)運(yùn)算執(zhí)行時(shí)長(zhǎng)為 100ms吐葵,但是通信時(shí)長(zhǎng)為 300ms规揪, 用了 Web Worker可能會(huì)更慢
比如新建一個(gè) web worker, 瀏覽器會(huì)加載對(duì)應(yīng)的 worker.js 資源,下圖中的 Time 是這個(gè)資源的通信時(shí)長(zhǎng)(也叫加載時(shí)長(zhǎng))
當(dāng)任務(wù)的運(yùn)算時(shí)長(zhǎng) - 通信時(shí)長(zhǎng) > 50ms温峭,推薦使用Web Worker
7猛铅、requestAnimationFrame 制作動(dòng)畫
requestAnimationFrame
是瀏覽器專門為動(dòng)畫提供的 API,它的刷新頻率與顯示器的頻率保持一致诚镰,使用該 api 可以解決用 setTimeout/setInterval 制作動(dòng)畫卡頓的情況
下面的案例演示了兩者制作進(jìn)度條的對(duì)比(運(yùn)行按鈕可點(diǎn)擊)
可以看到使用定時(shí)器制作的動(dòng)畫奕坟,卡頓還是比較明顯的
jcode
setTimeout/setInterval、requestAnimationFrame 三者的區(qū)別:
1)引擎層面
setTimeout/setInterval 屬于 JS引擎
清笨,requestAnimationFrame 屬于 GUI引擎
JS引擎與GUI引擎
是互斥的月杉,也就是說(shuō) GUI 引擎在渲染時(shí)會(huì)阻塞 JS 引擎的計(jì)算
2)時(shí)間是否準(zhǔn)確
requestAnimationFrame 刷新頻率是固定且準(zhǔn)確的,但 setTimeout/setInterval 是宏任務(wù)抠艾,根據(jù)事件輪詢機(jī)制苛萎,其他任務(wù)會(huì)阻塞或延遲js任務(wù)的執(zhí)行,會(huì)出現(xiàn)定時(shí)器不準(zhǔn)的情況
3)性能層面
當(dāng)頁(yè)面被隱藏或最小化時(shí)检号,setTimeout/setInterval 定時(shí)器仍會(huì)在后臺(tái)執(zhí)行動(dòng)畫任務(wù)腌歉,而使用 requestAnimationFrame 當(dāng)頁(yè)面處于未激活的狀態(tài)下,屏幕刷新任務(wù)會(huì)被系統(tǒng)暫停
8齐苛、JS 的6種加載方式
1)正常模式
<script src="index.js"></script>
這種情況下 JS 會(huì)阻塞 dom 渲染翘盖,瀏覽器必須等待 index.js 加載和執(zhí)行完成后才能去做其它事情
2)async 模式
<script async src="index.js"></script>
async 模式下,它的加載是異步的凹蜂,JS 不會(huì)阻塞 DOM 的渲染馍驯,async 加載是無(wú)順序的,當(dāng)它加載結(jié)束玛痊,JS 會(huì)立即執(zhí)行
使用場(chǎng)景:若該 JS 資源與 DOM 元素沒有依賴關(guān)系汰瘫,也不會(huì)產(chǎn)生其他資源所需要的數(shù)據(jù)時(shí),可以使用async 模式擂煞,比如埋點(diǎn)統(tǒng)計(jì)
3)defer 模式
<script defer src="index.js"></script>
defer 模式下混弥,JS 的加載也是異步的,defer 資源會(huì)在 DOMContentLoaded
執(zhí)行之前对省,并且 defer 是有順序的加載
如果有多個(gè)設(shè)置了 defer 的 script 標(biāo)簽存在蝗拿,則會(huì)按照引入的前后順序執(zhí)行,即便是后面的 script 資源先返回
所以 defer 可以用來(lái)控制 JS 文件的執(zhí)行順序蒿涎,比如 element-ui.js 和 vue.js蛹磺,因?yàn)?element-ui.js 依賴于 vue,所以必須先引入 vue.js同仆,再引入 element-ui.js
<script defer src="vue.js"></script>
<script defer src="element-ui.js"></script>
defer 使用場(chǎng)景:一般情況下都可以使用 defer,特別是需要控制資源加載順序時(shí)
4)module 模式
<script type="module">import { a } from './a.js'</script>
在主流的現(xiàn)代瀏覽器中裙品,script 標(biāo)簽的屬性可以加上 type="module"
俗批,瀏覽器會(huì)對(duì)其內(nèi)部的 import 引用發(fā)起 HTTP 請(qǐng)求俗或,獲取模塊內(nèi)容。這時(shí) script 的行為會(huì)像是 defer 一樣岁忘,在后臺(tái)下載辛慰,并且等待 DOM 解析
Vite 就是利用瀏覽器支持原生的 es module
模塊,開發(fā)時(shí)跳過(guò)打包的過(guò)程干像,提升編譯效率
5) preload
<link rel="preload" as="script" href="index.js">
link 標(biāo)簽的 preload 屬性:用于提前加載一些需要的依賴帅腌,這些資源會(huì)優(yōu)先加載(如下圖紅框)
vue2 項(xiàng)目打包生成的 index.html 文件,會(huì)自動(dòng)給首頁(yè)所需要的資源麻汰,全部添加 preload速客,實(shí)現(xiàn)關(guān)鍵資源的提前加載
preload 特點(diǎn):
1)preload 加載的資源是在瀏覽器渲染機(jī)制之前進(jìn)行處理的,并且不會(huì)阻塞 onload 事件五鲫;
2)preload 加載的 JS 腳本其加載和執(zhí)行的過(guò)程是分離的溺职,即 preload 會(huì)預(yù)加載相應(yīng)的腳本代碼,待到需要時(shí)自行調(diào)用位喂;
6)prefetch
<link rel="prefetch" as="script" href="index.js">
prefetch 是利用瀏覽器的空閑時(shí)間浪耘,加載頁(yè)面將來(lái)可能用到的資源的一種機(jī)制;通乘苎拢可以用于加載其他頁(yè)面(非首頁(yè))所需要的資源七冲,以便加快后續(xù)頁(yè)面的打開速度
prefetch 特點(diǎn):
1)pretch 加載的資源可以獲取非當(dāng)前頁(yè)面所需要的資源,并且將其放入緩存至少5分鐘(無(wú)論資源是否可以緩存)
2)當(dāng)頁(yè)面跳轉(zhuǎn)時(shí)规婆,未完成的 prefetch 請(qǐng)求不會(huì)被中斷
加載方式總結(jié)
async澜躺、defer 是 script 標(biāo)簽的專屬屬性,對(duì)于網(wǎng)頁(yè)中的其他資源聋呢,可以通過(guò) link 的 preload苗踪、prefetch 屬性來(lái)預(yù)加載
如今現(xiàn)代框架已經(jīng)將 preload、prefetch 添加到打包流程中了削锰,通過(guò)靈活的配置通铲,去使用這些預(yù)加載功能,同時(shí)我們也可以審時(shí)度勢(shì)地向 script 標(biāo)簽添加 async器贩、defer 屬性去處理資源颅夺,這樣可以顯著提升性能
9、圖片的優(yōu)化
平常大部分性能優(yōu)化工作都集中在 JS 方面蛹稍,但圖片也是頁(yè)面上非常重要的部分
特別是對(duì)于移動(dòng)端來(lái)說(shuō)吧黄,完全沒有必要去加載原圖,浪費(fèi)帶寬唆姐。如何去壓縮圖片拗慨,讓圖片更快的展示出來(lái),有很多優(yōu)化工作可以做
淘寶首頁(yè)的圖片資源都很小:
圖片的動(dòng)態(tài)裁剪
很多云服務(wù)赵抢,比如阿里云或七牛云剧蹂,都提供了圖片的動(dòng)態(tài)裁剪功能,效果很棒烦却,確實(shí)是錢沒有白花
只需在圖片的url地址上動(dòng)態(tài)添加參數(shù)宠叼,就可以得到你所需要的尺寸大小,比如:http://7xkv1q.com1.z0.glb.clouddn.com/grape.jpg?imageView2/1/w/200/h/200
圖片瘦身前后對(duì)比:
原圖:
1.8M
裁剪后:
12.8KB
經(jīng)過(guò)動(dòng)態(tài)裁剪后的圖片其爵,加載速度會(huì)有非常明顯的提升
圖片的懶加載
對(duì)于一些圖片量比較大的首頁(yè)冒冬,用戶打開頁(yè)面后,只需要呈現(xiàn)出在屏幕可視區(qū)域內(nèi)的圖片摩渺,當(dāng)用戶滑動(dòng)頁(yè)面時(shí)简烤,再去加載出現(xiàn)在屏幕內(nèi)的圖片,以優(yōu)化圖片的加載效果
圖片懶加載實(shí)現(xiàn)原理:
由于瀏覽器會(huì)自動(dòng)對(duì)頁(yè)面中的 img 標(biāo)簽的 src 屬性發(fā)送請(qǐng)求并下載圖片证逻,可以通過(guò) html5 自定義屬性 data-xxx 先暫存 src 的值乐埠,然后在圖片出現(xiàn)在屏幕可視區(qū)域的時(shí)候,再將 data-xxx 的值重新賦值到 img 的 src 屬性即可
<img src="" alt="" data-src="./images/1.jpg">
<img src="" alt="" data-src="./images/2.jpg">
這里以 vue-lazyload
插件為例
// 安裝
npm install vue-lazyload
// main.js 注冊(cè)
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// 配置項(xiàng)
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png', // 圖片加載失敗時(shí)的占位圖
loading: 'dist/loading.gif', // 圖片加載中時(shí)的占位圖
attempt: 1
})
// 通過(guò) v-lazy 指令使用
<ul>
<li v-for="img in list">
<img v-lazy="img.src" :key="img.src" >
</li>
</ul>
使用字體圖標(biāo)
字體圖標(biāo)是頁(yè)面使用小圖標(biāo)的不二選擇囚企,最常用的就是 iconfont
字體圖標(biāo)的優(yōu)點(diǎn):
1)輕量級(jí):一個(gè)圖標(biāo)字體要比一系列的圖像要小丈咐。一旦字體加載了,圖標(biāo)就會(huì)馬上渲染出來(lái)龙宏,減少了 http 請(qǐng)求
2)靈活性:可以隨意的改變顏色棵逊、產(chǎn)生陰影、透明效果银酗、旋轉(zhuǎn)等
3)兼容性:幾乎支持所有的瀏覽器辆影,請(qǐng)放心使用
圖片轉(zhuǎn) base64 格式
將小圖片轉(zhuǎn)換為 base64 編碼字符串,并寫入 HTML 或者 CSS 中黍特,減少 http 請(qǐng)求
轉(zhuǎn) base64 格式的優(yōu)缺點(diǎn):
1)它處理的往往是非常小的圖片蛙讥,因?yàn)?Base64 編碼后,圖片大小會(huì)膨脹為原文件的 4/3灭衷,如果對(duì)大圖也使用 Base64 編碼次慢,后者的體積會(huì)明顯增加,即便減少了 http 請(qǐng)求翔曲,也無(wú)法彌補(bǔ)這龐大的體積帶來(lái)的性能開銷迫像,得不償失
2)在傳輸非常小的圖片的時(shí)候,Base64 帶來(lái)的文件體積膨脹瞳遍、以及瀏覽器解析 Base64 的時(shí)間開銷闻妓,與它節(jié)省掉的 http 請(qǐng)求開銷相比,可以忽略不計(jì)掠械,這時(shí)候才能真正體現(xiàn)出它在性能方面的優(yōu)勢(shì)
項(xiàng)目可以使用 url-loader
將圖片轉(zhuǎn) base64:
// 安裝
npm install url-loader --save-dev
// 配置
module.exports = {
module: {
rules: [{
test: /.(png|jpg|gif)$/i,
use: [{
loader: 'url-loader',
options: {
// 小于 10kb 的圖片轉(zhuǎn)化為 base64
limit: 1024 * 10
}
}]
}]
}
};