目录
前文
在图片渐进式初探中,我们对比了jpg和png两种格式在渐进式和基准式加载方式上的区别。其中的实验页面为:旧实验页面。今天介绍下这个页面和新的改进。新的页面可以到实验页面
整体思路
一开始想通过DataURL进行长度截取,发现被encode后的图片链接直接截取会导致decode时出错,遂放弃。而采用后面的思路:服务器按指定规则输出图片,如:格式,加载方式,压缩比例和图片长度。通过控制图片长度,模拟渐进式加载的特定阶段。后端部分采用php,代码比较简单,图片处理可参考php图片处理Imagine常用例子。而控制长度部分则使用了ob_start缓冲区进行内容截取,而图片长度信息这里直接用cookie进行传输,而图片链接做key。
旧页面
主要代码
- add_image
在加载前,以图片参数为key做去重,未加载时,拼接图片链接去加载图片。
add_image:function(){
let item = {};
let params = [],title = [];
for(let k in this.query_data){
params.push(encodeURIComponent(k) + '=' + encodeURIComponent(this.query_data[k]))
title.push((this.key_text[k])(this.query_data[k]))
}
item.title = title.join('|');
let params_str = params.join('&')
if(this.image_arr.indexOf(params_str)>-1){
return
}
item.url = '/demo/image_interlace/image.php?'+ params_str;
item.params_str = params_str;
this.select_image.unshift(item)
this.image_arr.push(params_str)
}
- image_onload
图片加载完成后,以参数为key取得图片大小,更新到图片标题
image_onload(item,index) {
if(typeof this.select_image[index].image_length !="undefined"){
return
}
let url = item.url
let k = url.replace(/.*\?/,'')
let ret = window.document.cookie.match(new RegExp(encodeURIComponent(k)+'=(\\d*)'))
this.clearAllCookie()
if(ret){
item.image_length = (ret[1]/1024).toFixed(2) + 'kB';
}
this.select_image.splice(index,1,item)
}
缺点
- 每次都要加载一次图片
- 图片大小获取方式有点费劲
- 需处理cookie
新页面
思路
今天查文档时看到了fetch和Blob,突然想起我的这个页面,DataURL思路不行,那我为啥不转成Blob呢?说干就干。
主要代码
- add_image
同压缩质量的图片,最多完整加载4张,(png,jpg) * (渐进式,基准式)。图片加载完保存成Blob,在按指定加载长度进行截取,再通过URL.createObjectURL(Blob);显示图片。
add_image: async function(){
console.log(JSON.stringify(this.query_data))
let item = {};
let params = [],title = [];
for(let k in this.query_data){
title.push((this.key_text[k])(this.query_data[k]))
params.push(encodeURIComponent(k) + '=' + encodeURIComponent(this.query_data[k]))
}
item.title = title.join('|');
let params_str = params.join('&')
let origin_url_key = params_str.replace(/&percent=\d+/,'')
if(typeof this.origin_image_arr[origin_url_key] == "undefined"){
let response = await fetch('/demo/image_interlace/image.php?'+ params_str);
let myBlob = await response.blob();
this.origin_image_arr[origin_url_key] = myBlob
}
if(this.image_arr.indexOf(params_str)>-1){
return
}
let Blob = this.origin_image_arr[origin_url_key]
Blob = this.sliceBlob(Blob,0,(Blob.size * this.query_data.percent/100).toFixed(0))
item.url = URL.createObjectURL(Blob);
item.params_str = params_str;
item.image_length = Blob.size
this.select_image.unshift(item)
this.image_arr.push(params_str)
}
- sliceBlob
在低版本中, blob.slice会有兼容问题,做一下兼容处理。然而刚刚去翻blob.slice兼容性, 发现差不多也可以不用去处理,大部分支持了。
sliceBlob: function (blob, start, end, type) {
type = type || blob.type;
if(blob.slice){
return blob.slice(start, end, type);
}else if (blob.mozSlice) {
return blob.mozSlice(start, end, type);
} else if (blob.webkitSlice) {
return blob.webkitSlice(start, end,type);
} else {
throw new Error("This doesn't work!");
}
},
改进的点
- 在只调整加载比例的情况下,只需要从服务器加载一次图片
- 通过Blob.size获取图片大小更为方便
DataURL 和 服务器加载的区别
DateURL 可以通过 dataUrlToBlob 转换成 Blob,为啥不用呢。
- DataURL 大小差不多图片大小的4/3
- DataURL 只能对应一个压缩比例、一个类型和一个加载方式。比:60%压缩的渐进式png
- DataURL 需放在页面上,假定只要4张同压缩的图片,也太影响页面加载速度了
主要还是第二点,不灵活,不然这个页面用DataURL 挺好的,没几个人看,大就大点呗,还简单。还有就是我懒,不改了。