本人已經(jīng)使用vue.js半年多了,在做一些Html5頁面的時候發(fā)現(xiàn)很多頁面都是圖片組成的,如果能有效的壓縮圖片的體積那么整個項目體積就會減少很多,這是為什么寫這個簡單東西的起點。
Webp 百度百科上已經(jīng)講清楚在保持原畫質(zhì)的情況呀體積可以壓縮到原來的60%這是很牛逼的一件事??纯磜ebp的兼容情況,下圖是caniuse上面最新的webp支持情況

兼容情況還是不那么樂觀,不過chrome和安卓陣營已經(jīng)全部支持。所以我還是做了這件事。
源碼github
Vue.js 的自定義指令系統(tǒng)十分強大是我做這件事的根本原因之一,所以我的設(shè)想是在一個指令中傳入圖片鏈接,然后在頁面渲染的時候根據(jù)瀏覽器是否支持webp格式的圖片選擇下載那個圖片,這里就需要判斷瀏覽器是否支持webp了,這里我用到的是canvas方法,代碼如下
var canUseWebp = (function() {
var elem = document.createElement('canvas');
if (!!(elem.getContext && elem.getContext('2d'))) {
return elem.toDataURL('image/webp').indexOf('data:image/webp') === 0;
} else {
return false;
}
})();
這時候就非常簡單了指令在update的時候根據(jù)是否支持然后選擇不同的圖片
function update(el, option) {
var attr = option.arg || 'src';
if (el.tagName.toLowerCase() === 'img' && option.value) {
el.setAttribute(attr, option.value);
}
};
然而事情的這個時候發(fā)現(xiàn)一些小的圖標(biāo)不見了,原來我的webpack配置中設(shè)置了小于10k的圖片使用base64編碼,
所以最終我的更新代碼是這樣的
function update(el, option) {
var attr = option.arg || 'src';
if (el.tagName.toLowerCase() === 'img' && option.value) {
if (option.value.indexOf('data:image') < 0) {
var tmp = option.value.substring(0, option.value.lastIndexOf('.')) + '.webp';
el.setAttribute(attr, canUseWebp ? tmp : option.value);
} else {
el.setAttribute(attr, option.value);
}
}
};
這個時候vue.js 2.0發(fā)布了。我有針對 2.0版本做了支持,由于我的指令非常簡單,所以代碼很輕松
var isVueNext = Vue.version.split('.')[0] === '2';
if (isVueNext) {
Vue.directive('webp', function(el, binding) {
update(el, {
arg: binding.arg,
value: binding.value
});
})
} else {
Vue.directive('webp', {
bind: function() {},
update: function(val, old) {
update(this.el, {
arg: this.arg,
value: val
});
},
unbind: function() {}
})
}
};
這樣我的vue-webp指令就算完成了。
只有指令可不行,每次都要自己生成一份webp格式的圖片,這太不友好了。我有查找一番,發(fā)現(xiàn)一個webp-loader可以在webpack打包和dev的時候自動生成相應(yīng)的webp文件,太好了。使用原作者的webp-loader發(fā)現(xiàn)文件的hash不一樣,我又用imagemin最新版本升級了一下,上傳到npm叫webpn-loader(原諒我不會命名),
具體使用方法可以參考我的 Vue.js 2.0 后臺項目 模板項目
謝謝大家,看到這里。歡迎各種star