历史回顾:
- 【vue系列】从发布订阅模式解读,到vue响应式原理实现(包含vue3.0)
- 【vue系列】用 vue优雅地 生成动态表单(一)
- 【vue系列】优雅地用 vue 生成动态表单(二)
- 【vue系列】你不知道的 vue-devtools
- 【vue系列】vue-router源码分析
- 【vue系列】深入理解 vuex
- 【vue系列】vue 和 echats 结合的春天,vue插件vechart
- 【vue系列】vue2.x 项目配置 ESLint
- 【vue系列】vue2.x 项目配置 Mocha 单元测试
- 【vue系列】两张图,搞清楚 diff 算法,真香啊!
- 【vue系列】当 element-ui 按需引入遇到 vue-router 路由懒加载
- 【vue系列】封装公共弹窗组件的正确方式
- 【vue系列】开发组件、封装成vue插件、编写文档、配置gh-pages分支demo、发布npm包一波流
前言
最近有个对证件照、二维码进行裁剪上传需求,去查资料,有很多帖子对 xyxiao001/vue-cropper 插件的使用介绍。就去github上找到它,快速把需求开发上线了。笔者主要是对 vue-cropper 插件进行了二次封装。封装之后包含了点击选择图片、对图片进行base64转化、裁剪、以及调用后台接口上传。
图片裁剪需求开发中的疑问
笔者在开发的过程中留下了几处疑问,比如:剪裁框是如何透过蒙层看到底层的原图片的?拖动图片、收缩图片跟图片裁剪之间是如何处理的等等。大致梳理出来有以下疑问。
- 1.如何拖动图片,以及控制图片缩放的?
- 2.裁剪框是如何透过蒙层显示图片的?
- 3.如何生成截图框,截图的大小怎样控制?
- 4.如何清除裁剪框?
- 5.裁剪之后,如何生成图片呢?
- 6.选择图片上传图片,并展示?
- 7.为什么把图片转换为blob对象了?(todo)
- 8.如何自动裁剪截图?
- 9.手机端是如何控制手势缩放的?
vue-cropper 源码阅读
面对这些问题,要想知道答案,没有什么好办法,就是去读源码,边调试,边读源码。我的读源码习惯是,从源码的commit最初的提交开始看。其实有些疑问刚好是插件不断修复bug、扩展功能添加进去的。
1、如何拖动图片,以及控制图片缩放的?
针对这个问题,选了一个初始的commit版本,本地跑起来查看。
图片的拖动和缩放,是通过css3的 scale 和 translate3d(x,y,z) 控制的,每次改变的都是图片的外层div盒子,缩放和移动的也是这个外层div,而不是img本身。
图片的拖动控制,并没有绑定到图片上,或者图片的父级盒子上,而是采用了 cropper-drag-box 一个空div。在这个div上绑定了鼠标事件和触摸事件。这个疑问就解决了,来看下一个。
2、裁剪框是如何透过蒙层显示图片的?
猛地一看,笔者还以为是剪裁框透过蒙层看到了原图。其实这里是在剪裁框里还有一份原图,用于显示剪裁的部分。好奇的是为什么原图,跟剪裁中的原图移动的位置有差。
于是笔者去扒源码,看到 'translate3d('+ (x - cropOffsertX) / scale + 'px,' 原来是 原图片的当前的top的水平位置 - 裁剪框的top水平位置,哈哈哈,原来如此 😂
3、如何生成截图框,截图的大小怎样控制?
当点击开始裁剪就监听裁剪事件,记录裁剪框的初始位置,截图移动,通过当前位置减去初始位置,得到剪裁框的宽高,动态属性更新到裁剪框div的style上就好了。 还是很简单的。
4、如何清除裁剪框?
这就更简单了,用脚丫想想就知道,重置裁剪框上的style就可以了。去看了眼源码,果然如此。
5、裁剪之后,如何生成图片呢?
裁剪之后,通过创建 canvas ,调用 drawImage 来绘制,再使用 canvas.toDataURL("image/jpeg", this.outputSize) 来生成base64图片。
6、选择图片上传图片,并展示?
做过上传图片的的肯定都知道。不过这里还是科普下吧。
FileReader 可以异步读取文件,通过
FileReader.readAsDataURL()
开始读取指定的 Blob 中的内容。当监听到上传完成,result 属性中将包含一个data: URL格式的 Base64字符串 以表示所读取文件的内容。
7、为什么把图片转换为blob对象了?(todo)
看插件的提交记录,有一次commit提交,就是将图片转换为 blob对象,但是没说为什么这么处理。剪裁前的图片展示,为什么把图片转换为blob对象了?原来的base64不行么?笔者给作者提交了一个评论,说了笔者的疑惑。还没得到回复。
这里没想明白?清楚的、理解的可以私聊我(微信:uxiaoxiaoxx)
8、如何自动裁剪截图?
当图片被异步读取完成,就初始化裁剪框,按照裁剪框的默认位置进行裁剪。
9、手机端是如何控制手势缩放的?
主要采用的移动端 touches 控制,如果 e.touches.length == 2,则为两个手指进行缩放操作。
它的具体实现是:oldL 为两个手指的初始直线距离,newL 为两个手指的终止直线距离,
按照 cha = ~~(newL - oldL) 的cha比例系数计算图片放大缩小的倍数 😁
扩展:
Math.sqrt() 函数返回一个数的平方根;
Math.pow() 函数返回基数(base)的指数(exponent)次幂
小结
日常业务需求开发,大部分的开发者就可以做,可是,做这样的事情,我们该怎么提升自己?让自己有所成长?首先我们能在需求开发中的深度思考,抛出疑问,然后通过阅读源码(或者重构封装),来解答自己的疑惑,这是自我提升的一种方式。希望我的学习方法,能带给你一点启示。共勉!最后,感谢xyxiao001对vue-cropper贡献。