项目是基于vue2的前端框架,由于原先文章页面渲染是直接把请求过来的数据(含有html标签的字符串)放到v-html中渲染,图片和文本一起渲染造成页面渲染过慢,因此想到用图片懒加载和转换webp格式,来进行优化。由于我们网站的图片是放在七牛云存储,所以本例子的图片处理是结合七牛的sdk的。
第一步,调整页面渲染结构,图片和文本分开
<template>
<div id="test">
<div v-if="!!content" v-for="item in content">
<div v-html="item.text" v-if="item.text != ''"></div>
<img v-lazy="item.imgSrc" alt="" v-if="item.imgSrc !=''" style="max-width:100%;"> <!--这里图片懒加载运用的是vue-lazyload-->
</div>
</div>
</template>
content的数据格式为
content({
text : [不含img的字符串组成的数组],
imgSrc : [img的src地址字符串组成的数组]
})
第二步,判断当前浏览器是不是支持webp格式
created(){
let self = this;
//检查当前浏览器是不是支持webp
self.checkWebpFeature('lossy', function(feature,result){
self.isWebpView = result;
})
},
//'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
//“功能”可以“有损”之一,“无损”,“α”或“动画”。
//判断浏览器是不是支持webp格式
checkWebpFeature(feature, callback) {
let kTestImages = {
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
};
let img = new Image();
img.onload = function () {
let result = (img.width > 0) && (img.height > 0);
callback(feature, result);
};
img.onerror = function () {
callback(feature, false);
};
img.src = "data:image/webp;base64," + kTestImages[feature];
},
第三步,对从服务器请求过来的文章数据进行操作
amendStr(str){
let arr = str.match(/<s?img[^>]*>/gi) //匹配到字符串中的所有img
let arrSrc = [];
let arrText = [];
//遍历匹配到的img
for(let i=0;i<arr.length;i++){
if(this.isWebpView){ //当前浏览器支持webp渲染
arrSrc.push(arr[i].match(/src=[\'\"]?([^\'\"]*)[\'\"]?/i)[1]+'?imageView2/1/format/webp/interlace/1&attname=1.webp')
}else{
arrSrc.push(arr[i].match(/src=[\'\"]?([^\'\"]*)[\'\"]?/i)[1]+'?imageView2/1/format/png/interlace/1&attname=1.png')
}
}
str=str.replace(/<s?img[^>]*>/gi, '&**&');
arrText = str.split("&**&")
let arrContent = [];
let length = arrSrc.length > arrText.length ? arrSrc.length : arrText.length;
for(let i=0;i<length;i++){
arrContent.push({
text : arrText[i] == undefined ? '': arrText[i],
imgSrc : arrSrc[i] == undefined ? '': arrSrc[i]
})
}
this.content = arrContent;
arrSrc = null;
arrText = null;
arrContent = null;
},
检查浏览器是不是支持webp格式用到的checkWebpFeature方法出自Google官方文档。
七牛云存储的图片格式转换参考:图片处理API
全部的demo组件代码如下:
<style scoped>
#test{
background: #999;
margin: 0 auto;
width: 800px;
}
</style>
<template>
<div id="test">
<div v-if="!!content" v-for="item in content">
<div v-html="item.text" v-if="item.text != ''"></div>
<img v-lazy="item.imgSrc" alt="" v-if="item.imgSrc !=''" style="max-width:100%;"> <!--这里图片懒加载运用的是vue-lazyload-->
</div>
</div>
</template>
<script>
export default {
data(){
return {
content: null,
isWebpView:false, //浏览器是否支持webp格式渲染
}
},
created(){
let self = this;
//检查当前浏览器是不是支持webp
self.checkWebpFeature('lossy', function(feature,result){
self.isWebpView = result;
})
},
mounted(){
this.getContent();
},
methods:{
//'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
//“功能”可以“有损”之一,“无损”,“α”或“动画”。
//判断浏览器是不是支持webp格式
checkWebpFeature(feature, callback) {
let kTestImages = {
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
};
let img = new Image();
img.onload = function () {
let result = (img.width > 0) && (img.height > 0);
callback(feature, result);
};
img.onerror = function () {
callback(feature, false);
};
img.src = "data:image/webp;base64," + kTestImages[feature];
},
getContent(){
let self = this;
this.$http.get('/api/test/content').then((response) => {
self.amendStr(response.body)
})
.catch(function(response) {
console.log(response.body)
});
},
amendStr(str){
let arr = str.match(/<s?img[^>]*>/gi) //匹配到字符串中的所有img
let arrSrc = [];
let arrText = [];
//遍历匹配到的img
for(let i=0;i<arr.length;i++){
if(this.isWebpView){ //当前浏览器支持webp渲染
arrSrc.push(arr[i].match(/src=[\'\"]?([^\'\"]*)[\'\"]?/i)[1]+'?imageView2/1/format/webp/interlace/1&attname=1.webp')
}else{
arrSrc.push(arr[i].match(/src=[\'\"]?([^\'\"]*)[\'\"]?/i)[1]+'?imageView2/1/format/png/interlace/1&attname=1.png')
}
}
str=str.replace(/<s?img[^>]*>/gi, '&**&');
arrText = str.split("&**&")
let arrContent = [];
let length = arrSrc.length > arrText.length ? arrSrc.length : arrText.length;
for(let i=0;i<length;i++){
arrContent.push({
text : arrText[i] == undefined ? '': arrText[i],
imgSrc : arrSrc[i] == undefined ? '': arrSrc[i]
})
}
this.content = arrContent;
arrSrc = null;
arrText = null;
arrContent = null;
},
},
}
</script>