图片优化技巧
[视频] 你好,我是李艺。 上节课我们主要学习了如何使用本地缓存数据及如何优化网络请求的优先级顺序,这节课我们学习图片相关的优化技巧。 先看一下问题,随着网络的普及及用户带宽的提高,用户对图片清晰度的需求也越来越高,一张高分辨率的图片如果没有经过任何的压缩处理,动辄就是几MB 甚至十几MB的大小,当我们把这些图片用于小程序的本地图片时却是致命的,一个小程序的代码包最大也不过是2MB的大小,图片优化主要可以从以下这几个方面进行着手: 一 、尽量减少图片的请求次数 二、尽量压缩图片的大小 三、尽量使用带有CDN加速的网络图片链接 四、尽可能使用高压缩比的图片,例如webp格式的图片 下面我们看代码实践 。 首先看实践一,生成雪碧图。 这里的雪碧图与饮料没有一点关系,它们只是凑巧翻译自同一个英文单词Sprite,那么什么是雪碧图呢?雪碧图就是人为地将多张小图片拼接成一个大图片,在使用的时候一次性在客户端完成加载,利用CSS的background-image样式只显示图片的某一块区域的这样的一个技术,从而实现在多个元素上复用一张图片,减少图片的加载请求次数,miniprogram-slim是一个微信团队推出的小程序资源瘦身工具,下面我们就使用这个工具实现雪碧图的生成。首先我们需要安装这个模块,安装指令如屏幕上所示,在安装以后,我们就可以使用子指令sprite生成雪碧图了,生成的指令如屏幕上显示的这样,生成的sprite.png图片是由多张小图片自动排列而成的,如我们屏幕上展示的这样是它的一个生成的效果。虽然有时候看起来图片区域的利用率不是很高,但整体上来讲效果已经不错了,小图片的排列布局是自动生成的,本质上生成的图片效果是由参与合成的小图片它们来决定的,与雪碧图同时生成的还有一个sprite.css文件,这个文件包含了所有子图片的使用样式如屏幕上所示,在生成的样式文件里面各个图标的偏移量都已经写好了,在使用的时候直接拷贝这些样式,然后稍加修改就行了。如果我们愿意,可以将任意多张的图片拼接成一张图,不管原图它是大是小。 下面进行实践一的代码演示。 首先我们看一下最终写成的代码,这是我们最终的一个代码,在tools这个目录下面有一个static这样的静态资源目录,然后有一个generate_sprite.sh这样的一个脚本文件,在这个脚本文件我们使用miniprogram-slim,然后调用它的子指令sprite进行了一个雪碧图的生成,这是我们的一个代码,我们可以将这个代码先拷贝一下放在我们目前的这个项目目录下面,找到tools目录拷贝在这个地方,然后我们再看一下静态目录,静态目录我们不需要从这里拷贝,因为本身在我们小程序项目里边也有一个静态目录,可以切到我们项目里边,然后找到本地static静态目录,将这个目录拷贝到tools下面,现在就已经过来了,再看一下我们相关的模块,安装以后的模块在这个文件里面没有显示,本质上它是要有这个的,然后我们再往后看一下,打开这个,这个也没有,我们再往后找一个,这是另外的一个,这个我们可以进行全局安装,打开我们目前的tools,在这个目录下打开集成终端环境,然后使用yarn global add进行安装,如果我们知道版本号的话最好把版本号给它带上,现在我们就可以安装了,这个版本号稍后安装以后,我们就知道它大概的一个版本号信息了,另外我们还需要一个本质上这个模块工具,它还需要一个叫做libpng的第三方模块,这个也是需要提前安装,现在我们可以看到了我们这个版本是1.0.1,你在安装的时候最好把后面的版本号也给它带上,这样保证效果的一致性,下面我们再用brew安装另外的一个libpng这个模块,brew是Mac OS上面的一个包管理工具,本质上我们装的libpng它不是一个Node.js模块,所以我们拿这个来进行安装,安装以后这样就可以了,接下来我们就开始去调用我们先前已经生成的generate_sprite.sh这样的一个脚本了,执行脚本generate_sprite.sh,然后执行,脚本里面我们可以看一下,我们是以static也就是它当前目录下static里面的icons目录,它里边所有的这些图标文件作为输出的这些小图片,同时这一个-o它指定的是我们输出的目录,就是输出到我们当前这个目录下,现在这个指令已经执行完了,我们看一下在我们当前的tools目录下面多了两个文件,一个是sprite.png,这是我们生成的雪碧图,另外还有一个sprite.css文件,这个文件我们可以看一下它里面会有一些类样式 ,每个类样式都标注了背景图的一个偏移量,还有它的宽高,有这些信息以后,基本上我们在使用这张图片的时候就可以将这张图片作为背景,应用于不同的组件了,有它的起点以及区域所占的宽高大小就可以指定使用某一块区域了 ,它是这样的一个工作原理,代码演示我们就说到这里。 下面我们看实践二,图片压缩。 看完雪碧图的生成,下面我们看图片压缩,要想压缩图片,有现成的在线压缩网站,例如现在我们屏幕上看到的链接就可以使用,在本地无网络的状态情况之下也可以使用离线的压缩工具,我们将小程序项目下面的静态目录static拷贝至tools目录下面以后可以运行compress.sh这样一个脚本,就可以在dist目录下看到压缩之后的图片了,compress.sh脚本是使用miniprogram-slim模块的子指令imagemin完成这个图片压缩功能的,其脚本主要内容如我们屏幕上显示,子指令imagemin的运行依赖libpng模块,如果本地还没有安装这个模块则需要在执行压缩脚本之前进行安装,以Mac OS系统为例,我们可以使用包管理工具brew进行安装,安装指令如屏幕上所示,压缩并不是优化的终点,图片无论怎么压缩终究它还是会占用本地代码包的大小,小程序里面的图片的终极优化还是得依靠网络图片。 下面我们进行实践二的代码演示。 首先我们看一下最终的我们编写的压缩脚本,在我们的最终源码目录里我们可以找到,在这个tools子目录下有一个叫做compress这样的一个脚本,将这个脚本文件我们复制一下拷贝到我们当前的目录下面,看一下这个文件,这个文件里面的脚本是调用了miniprogram-slim它的一个子命令imagemin这样的一个子命令,然后我们以static目录下的文件,就是所有的文件 png的文件作为输入,同时指定压缩的图片的质量,然后将所有的文件然后输出到当前目录下的dist,这样的一个目录下是我们的写的这样的一个压缩的脚本,当然在使用这个脚本之前仍然需要确认在本地已经使用yarn global add这个模块,后面我们最好加上版本号1.0.1,这是我们目前在使用的版本号,这个模块安装以后,接下来我们还需要使用本地的包管理工具brew,然后install libpng 这个模块也需要安装,因为我本地已经安装了,这个指令就不需要重复执行了,这两个模块安装以后,接下来我们就可以执行compress指令了。 我们用bash执行它会显示一个结果,13个图片被处理,我们看一下这个目录下面会有很多的一些图片,包括icon图片,还有我们的程序里面用到的一些商品图片都包含在这个地方了,但是它这个里边它没有进行一个分组 没有分目录,所以需要我们自己去处理,这个文件搞完以后可以将这些程序用到的这些图片拷贝一下,然后到我们的当前的小程序的静态目录下,images 到这个目录下进行粘贴,因为粘贴它会重新起名,所以我们就原来的全部给它删掉,将这些图片先给它删除,然后再拷贝一下,把这些图片给它拷贝一下放在这个目录下,另外还有一些icon图片,这些图片我们也拷贝一下放在这个icons这个目录下面,这个拷贝的体验不是很好,拷贝过来了,另外还有两个,这两个其实应该在这个icons这个目录下面,我们把它移过来这样就可以了,全部修改完成以后,在我们微信开发者工具里面单击一下编译按钮,看一下最终的结果。 主要看我们这个图片的一个效果,没有问题,基本上没有问题,这个地方有问题,我们无法定位list,icons/list.png图片,这个图片可能有缺失,我们把它再补全一下,这个图片是有的,我们可以清一下编译缓存然后再刷新一下,这个地方它仍然会显示我们无法定位/static/icons/list.png,我们再查看一下/static/icons/list.png,这个里面还是少了一个 少了一个list.png图片,我们可以从最终的目录里边找到这个文件放在这里,然后再刷新一下,现在已经没问题了,这个代码演示就到这里。 下面我们看实践三,使用腾讯云cos存储本地图片。 下面使用腾讯云的cos对象存储服务将本地图片转化为网络图片,首先我们需要实现上传本地图片至腾讯云cos存储的方法,uploadImageToCos,最终这个代码如屏幕上所示,这个方法是基于官方的cos-sdk的Node.js脚本实现的,另外我们再创建一个upload.js文件,并且在这个文件里面实现一个uploadImageToCos函数,实现以后这个代码如屏幕上所示,upload.js文件主要用于遍历本地的static目录,将本地图片自动上传至腾讯云对象存储服务器,在使用upload.js脚本之前我们还需要做一些有关账号的准备工作,首先我们需要去腾讯的官方网站开通对象存储服务并创建一个默认的存储桶,这里我们不必担心花钱的问题,因为新用户他有一定的免费额度,上手是没有任何困难的,开通以后要到用户中心-访问管理-访问密钥,API密钥管理这个地方拿到一组SecretId和SecretKey信息,并把这两个信息写到本地的环境变量里面去,这一步是为了让源码中的环境变量读取代码可以生效,这个读取代码如屏幕上所示,稍后我们在代码演示的时候也会看到。 成功运行upload.js文件以后会得到一个cos_urls.json这样的一个文件,在这个文件里边存储了图片上传前的地址以及上传后的网络地址,还包括webp格式的网络地址,其内容结构如屏幕上所示,在拿到了图片的webp网络链接以后就可以到项目中进行使用了,将原来的本地图片链接都修改为线上的网络链接,例如在后端接口返回的数据当中就有不少的本地链接都是可以修改的,在给image组件换链接的时候,如果使用webp地址,我们还要注意要将image组件的webp属性打开,默认情况下这个属性它是关闭的,为了方便替换我们可以使用Node.js再写一个额外的处理脚本,脚本内容如屏幕上所示,replace.js文件是一个根据生成的cos_urls.json文件,批量将本地文件中的本地地址替换为webp云链接的一个脚本文件,在这个文件里边dealWithDir是要处理的目录,变量localToCloud控制是否是从本地向云端链接进行转换,还是反过来从云端链接向本地进行转换,找到我们最终源码的目录,在这个下面首先我们要看第一个文件是upload_img_to_cos.js这样的一个文件,这是一个js文件,这个文件里边我们用到了一个腾讯cos官方的一个cos-sdk,这是它的一个Node.js版本,目前这个版本是v5这样的一个版本,使用之前我们首先要在我们当前的项目目录下进行这个模块的安装,跟之前一样,我们安装的时候最好也要指定它的一个版本号,也就是2.11.6这样的一个版本号,我们看一下当前项目下的这个tools目录,安装指令就是yarn add,然后是这个模块名,后面跟版本号2.11.6,把这个给它装上,这一步装上以后还需要创建几个文件,第一个是这个文件,第二个是upload.js文件,第三个我们还需要有一个replace文件,这个文件也是需要的,将这三个文件给它拷贝一下放在我们当前的tools目录下。 首先我们看一下upload_img_to_cos.js这个文件,这个文件调用这个sdk,然后这个地方是从我们本地环境里面去取我们的两个环境变量,这两个环境变量现在我们还没有设置,稍后我们从腾讯的cos后台拿到这两个信息以后还要在终端里面进行设置,这是两个信息 这两个信息具备以后我们这个地方定义了一个uploadImageToCos的这样的一个函数,这个函数里面主要使用主要的一个功能就是调用前面引入的cos-sdk进行一个图片的上传,将我们本地的图片上传至腾讯云的cos对象存储,这里面有些信息,第一个地方这是存储桶的名字,这个名字稍后我们在cos后台可以看到,然后这个是存储桶所在的区域,这个区域也是我们创建存储桶的时候所选择的,在后台里面也可以看到,这个地方Key这个文件名 这是我们必须的设定的,是由我们自己来设定的,前面这个images是我们存储桶里边一个自定义的子目录的名字,然后这个上传模式我们选择标准模式,上传对象就是file,这是它主要的一个上传代码,上传以后它会进行返回,把这个信息进行一个拼接,在这个地方拿到这个上传之后的在线链接以后,它的webp格式本质上它其实是在我们原有链接之后,后面加了一些特殊的后缀将它变成了webp的这种格式,这是这样的一个代码,然后最后是将它导出。 下面我们再看upload.js这个文件,我们是去遍历我们本地的一个目录,这个目录我们是遍历我们上级目录下的static,也就是说我们真正的小程序本身遍历它静态目录 ,然后引入我们前面自己写的方法去循环读取我们这个目录,拿到下面的这些文件,拿到文件以后,当然这个文件我们还做了一些后缀的过滤,我们只允许上传这些后缀的文件,过滤以后我们就开始上传了,拿到以后开始有一个循环,将这文件循环,循环以后我就上传,上传以后得到一个上传的结果,拿了一个结果,这个结果再去写到本地的一个cos_urls.json这样的一个文件里面 ,这是我们上传代码。 下面我们到腾讯云的cos后台看一下我们需要准备的一些信息、密钥等等一些信息。打开腾讯云的网站cloud.tencent.com 以后,首先要找cos 就是对象存储,第一次打开的时候是没有存储桶的,所以我们要按照提示去创建一个存储桶,创建以后在存储桶列表里面会有我们默认的存储桶,其中这个地方我用的是cloud,然后连字符跟一串数字,这个存储桶我们单击进去会看到它相关的一些信息、基础配置,打开概览,这个是存储桶的一个名称,然后这个地方有一个ap-beijing,这是我们前面在那个代码里边看到的,跟这个是一样的,它所属的一个地域在代码里面也要写,这个地方存储桶的名称刚才我们的代码里面也看到了,这两个信息都是需要的,另外还有一个是我们这个文件列表,可以单击看一眼,这个地方它有一个images的子目录对不对,因为我们自定义的key在代码里面自定义key 前面加上这样的一个前缀,这样就可以将我们这个图片上传到这样的一个子目录下,这是一个很重要的信息,除了这些信息以外,接下来还有一个很重要的信息,就是我们要选择右上角头像这里有一个叫做安全设置,选择安全设置 ,然后再选择访问管理,然后再选择访问密钥,下面有一个API密钥管理,选择这个,这个地方默认它是没有密钥列表的,我们如果没有的话,第一步我们要选新建,新建以后,这个地方如果说你之前新建了还可以选择显示,SecretId和SecretKey 这两个信息拿到以后,接下来我们要去设置本地的环境变量,打开我们本地的,当然我这个系统是Mac OS,在其他系统上要设置,例如在Windows上面要设置系统的环境变量去设置,打开这个文件,在这个地方我们可以看到有一个export COS_SecretId等于它,下面这个是类似的COS_SecretKey等于它,这两个信息输出搞定以后,接下来我们就可以回到我们代码里面了,也就是在我们的上传代码,最上面这个地方,有了那两个环境变量以后,这个地方它就可以取到真实的密钥信息了。 为什么要把密钥信息放在我们环境变量里面,其实直接放在这里也是可以的,本地测试可以放在这里,我这里是为了防止密钥信息在这个仓库里面不小心外露去设置的放在这里的,这一步改完以后,接下来我们就可以执行我们upload.js文件了,这个文件它本身是一个js文件,我们可以拿node去执行,node upload.js运行以后,这个速度很快,因为这得益于我们的网速很快,所以它很快。拿到这个文件我们可以格式化一下,这是一个json文件,格式化以后我们可以看到这里面是一个列表,这个列表的每一项它包含四个信息path,这个path是我们本地的一个地址,然后是name 图片的名称,imgUrl是我们线上的地址,webpUrl是我们的webp格式的一个地址,如果单击这个链接的话,在浏览器里面是可以打开、查看图片的,后面这个也是一样,只不过是这个格式不一样。因为谷歌浏览器它本身支持这种格式,所以查看这种图片是没有问题的,这一步都搞完了,接下来我们接着再搞另外的一个文件,就是replace.js。本质上搞完前面那一步拿到这个结果以后我们就可以替换了,但是如果我们要替换的信息很多的话,这一步也比较累,所以我们再进一步,就写一个replace.js这样的一个脚本,这个脚本的作用它是自动将我们某一个目录下的,里边的本地链接,然后进行一个替换,这是我们主要的一个目的,我们替换的时候,其实它是有一个路径的比对的,有个路径的比对的。如果我们这个路径它不一样的话,它其实是很难去把它给替换掉的,比如说我们现在接下来想替换的一个是这个,我们导航组件,我们先打开我们导航组件,看一下我们这个目标文件,看一下它本身它有哪些本地图片链接,这个是它本地的链接对不对,这个是它本地链接,然后我们需要将这个,还有后面这些都给它替掉,都给它替掉,我们先执行一下,执行一下我们replace这个文件,先替换,看它的一个表现,node replace.js,然后会有一个输出,会有个输出,就是我们大概替换了哪些文件,替换的结果在哪里,替换结果在哪里。看一下我们这个文件,replace.js这个文件,看这个文件我们主要是怎么样去做的一个替换,读文件,这个是获取列表,然后获取所有的图片,然后这个是读取json的一个信息,创建目录,然后这个地方这是我们的主要的代码 在这个地方,然后我们这个地方是取里面的一些路径,取我们要替换的文件里面的一个路径,然后进行replace一个替换,本质上我们要查它里面是不是有这个地址,结果是已经处理了,我们这个地方会有一个打印,已经处理什么,一个path,可以看一下。这样一个信息它会有一个打印,这个地方好像,好像并没有打印,再次执行一下,好像没有,我们前面的这个打印,它其实是我们里边的console.log,这些信息都是有打印的。但是我们后面这个,它并没有打印对不对,并没有打印,它并没有打印,可能跟我们的文件里边,我们现在地方 这个信息跟它可能是有关系的,我们可以改写我们的代码也是可以的,因为把前面这个前缀给它去掉,当然我们在这个地方给它手动给它替掉也是可以的,然后这两项给它加上,然后全部替掉,现在就变成这样的一个链接了 。 我们再执行一下替换,这个地方就已经处理,处理完以后看一下目标文件,这个地方没有,在tools/dist目录下生成了一个文件,在这个下面有miniprogram。注意我们这个地方iconPath,selectedIconPath这两个都已经替掉了,这是我们替换之后的文件,我们可以将这个文件的内容给它拷贝一下覆盖到我们这个里面 ,这样就完成了导航组件的本地网址的替换。接下来我们再干第二件事情:替换另外一个目录,仍然是找到我们replace.js,把上面处理目录给它替掉,然后注释掉、打开,把它上面给它打开,下面这个给它注释掉,这个目录是我们后台,这个文件我们看一眼 ,在server controllers,api home这个文件里面,其实有不少的本地地址,我们可以搜一下static开头的,看有很多都是这些路径,现在我们要处理它,仍然执行这个,已经处理了,处理完成以后 然后在我们的 找一下tools,server这个目录下这有一个home.go这个文件,可以再查看一下这个地方所有的图片,这个地方看到没有,已经变成了线上的地址,已经变成网络链接了,我们将这个文件给它拷贝一下到我们这个服务器端这个程序目录下,将这个文件给它替掉,替掉以后,因为我们后端有热加载,原理上它会重新编译,我们打开这个地方再重新编译。 这一块处理完了,还有一个地方我们需要处理,在我们的小程序这个项目目录下我们有一个云函数,云开发目录下有一个叫做getHomeData这个文件,这个文件里面也有一些信息,看到这些、还有这些也需要处理,处理方法是一样的,找到我们的万能的replace.js文件,找到它拷贝一下,上面给它注掉,这个地址我们要变一变了,可以先拷贝一下它的相对路径粘到这个地方,然后这个地方我们要改写一下,当前的tools它的一个父目录下,父目录就是这个,所以把这个1给它去了,这样后面要加一个斜杠,代表它是目录,搞完了,然后再回到我们刚才执行脚本的终端再执行一下它,这个地方也已经处理了 对不对,我们查看一下最终的目录,它的文件这些已经替换了,把这个文件拷贝一下回到我们云开发,云函数 index.js ,覆盖完成了,所有的修改都完成了,现在我们单击编译按钮重新查看运行效果。 这是首次它编译所需要的出现的错误不用管它,再单击一下;怎么检查我们的图片是不是从网络加载的,可以看Network面板,Network面板里面它有一个Img标签,我们可以看这里边这些,这不都是有一些从网络上加载的地址,在这个地方我们还有两个地方需要修改:第一个是我们导航组件,我们这个里边不是用了image,我们要把它的什么 webp,webp属性给它打开,因为我们用的地址都是webp地址,这是一个。另外还有一个是在我们首页,看一下首页,这里,这个里面我们也用了,我们搜一下所有的图片,这个地方加上一个webp,然后再往下找,这个地方有了,这个也有了,确保所有的都有这个属性,这个代码演示我们就说到这里。虽然代码演示的内容有点多,但是并不复杂,相信你耐心进行操作的话也可以完成。 下面我们看小结,雪碧图在游戏开发里面使用较多,在小程序开发里面使用不是很普遍;一方面是由于每次修改图片以后 需要重新生成雪碧图,这样比较麻烦。另一方面小程序里面的本地图片,是在代码包里面整包下载的,它并不是单张一个一个分别下载的,这样一来生成雪碧图的意义就不是很大了。图片压缩是普遍需要的一个技巧,图片在上传腾讯云对象存储之前,还可以先进行一番无损压缩,这样多少还可以节省一些存储空间,图片上传以后,在使用webp格式的一个链接的时候,图片本身也存在压缩,这在一定程度上也切实减轻了小程序网络资源请求的压力,这节课我们就讲到这里。 点击查看文档: ● https://github.com/wechat-miniprogram/miniprogram-slim ● https://cloud.tencent.com/product/cos 上面的网址就是本课涉及到的文档地址,这节课我们主要学习了有关图片的优化技巧,下节课我们学习如何使用小程序助手。 最后我们看一下思考题,这里有个问题请你思考一下,我们知道在setData更新数据后。 触发的重渲染机制,会严重阻塞页面视图的即时渲染效率,但是有一类原生组件,它们是有原生的Context节点,可以使用标准的SelectorQuery查询得到,并且使用它们可以绕过底层的数据中转,直接更新视图节点,你知道这个技巧是怎么使用的吗? 下节课(对应9.2)我们就一起来深入探讨一下这个问题。