原生js实现html5图片拖拽裁切可用vue或react附源码下载

来源:程序思维浏览:1701次
如今的H5运营活动中,有很多都是让用户拍照或者上传图片,然后对照片加滤镜、加贴纸、评颜值之类的。尤其是一些拍照软件公司的运营活动几乎全部都是这样的。



博主也做过不少,为了省事就封装了一个简单的图片拖拽、裁剪的插件。其实网上也有很多类似的插件,只不过有的功能冗余体积大,有的甚至还依赖jquery。索性自己搞一个轻量的,只是不支持缩放功能。

这里简略说下实现过程,只截取部分代码片段,有兴趣的可以看下原码,反正也很简单。

图片上传

这个DEMO里使用的上传方式是HTML5的 File Input,但是很多运营活动需要调用微信的上传&拍照接口,由于以前踩过坑这里就啰嗦两句,帮助新人绕开。

· 在 wx.config 中的 jsApiList 属性中添加 chooseImage 和 uploadImage API。

· 调用 chooseImage API,获得 localId。

wx.chooseImage({
    count: 1, // 默认9
    sizeType: ['original', 'compressed'],
    sourceType: ['album', 'camera'],
    success: (res) => {
        var localIds = res.localIds[0];
        console.log(localIds);
    }
});

需要注意的是这里的 localId 可以通过 img 标签的 src 属性进行展示,但是无法传给服务器接口或者通过 canvas 裁剪,所以还需要上传一步。

· 调用 uploadImage API,将之前得到的 localId 传入,获得 serverId。

wx.uploadImage({
    localId: localIds,
    isShowProgressTips: 1,
    success: (res) => {
        var serverId = res.serverId;
        console.log(serverId);
    }
});

有了 serverId 其实就可以得到保存在微信服务器上的图片了,只是博主之前还去多余的下载一道。

将一开始微信认证时获得的 accessToken 与 serverId 拼接到下面的链接即可直接引用

const imgUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id=" + serverId;
接下来就可以创建 image 对象,设置 src 属性,完成拖拽裁切等操作。

初始化

首先要对图片的尺寸进行调整:

· 若图片宽高比比容器的大,即图片比容器“扁”,就让图片的高度与容器保持一致,宽度自动适应保持原图比例不变

· 若图片宽高比比容器的小,即图片比容器“瘦”,就让图片的宽度与容器保持一致,高度自动适应保持原图比例不变

为了便于理解,我们假设容器高宽为1:1,为下图中红色线框区域:





var img = new Image(),
    _this = this;

img.src = imgUrl;
img.style.webkitUserSelect = 'none';

img.onload = function() {

    var imgWidth = img.width,
        imgHeight = img.height,
        imgRate = imgWidth / imgHeight,
        conRate = conWidth / conHeight;

    if (imgRate > conRate) { //宽型

        var imgCurrentHeight = _this.opts.conHeight,
            imgCurrentWidth = imgCurrentHeight * imgRate,
            maxOffset = conWidth - imgCurrentWidth;

        img.setAttribute('width', 'auto');
        img.setAttribute('height', _this.opts.conHeight);

        //......

    } else { //高型

        var imgCurrentWidth = _this.opts.conWidth,
            imgCurrentHeight = imgCurrentWidth / imgRate,
            maxOffset = conHeight - imgCurrentHeight;

        img.setAttribute('width', '100%');

        //......
    }
}

上述代码就完成了基本的图片大小调整,其中 conWidth, conHeight 是插件接收的容器高与宽,maxOffset 是图片允许拖拽的最大偏移量。

拖拽

这里我使用了一个比较轻量的手势库——hammer.js,通过手势的位移改变图片的 translate 属性值。

这里只截取横向拖拽的代码片段,纵向类似

复制代码
hammer.on('pan', function(e) {
    var current = img.style.transform ? img.style.transform.split('(')[1].split('px')[0] : 0,
    move = Number(current) + (e.deltaX * (_this.opts.speed/10));

    if (move >= 0 || move <= maxOffset) {
        return;
    }

    img.style.transform = 'translateX('+move+'px)';

    _this.cutData.moveX = Math.abs(move);
    _this.cutData.moveY = 0;
});

opts.speed 值为插件初始化时设置的拖动速度,这里速度值算法比较简单,有兴趣的朋友可优化使其更平滑些。cutData 用于缓存拖动的位置,用于之后的裁剪。

裁剪

这里使用了 canvas 对图片进行裁剪返回 base64码,可以将 base64码直接展示或者通过 POST 接口传到服务器处理(GET请求长度会超)

cut: function() {
  var canvas = document.createElement('canvas'),
    img = document.querySelector('#cutImgObj'),
    data = this.cutData,
    cutWidth = this.opts.conWidth / data.scaleRate,
    cutHeight = this.opts.conHeight / data.scaleRate;

  canvas.width = cutWidth;
  canvas.height = cutHeight;

  canvas.getContext('2d').drawImage(img, data.moveX/data.scaleRate, data.moveY/data.scaleRate, cutWidth, cutHeight, 0, 0, cutWidth, cutHeight);
  return canvas.toDataURL('image/png');
},

这里要说明下,由于图片进行了缩放,所以需要将画布调整到原图的尺寸,同时记录的拖动位置也需要除以缩放比例。

调用

· 初始化

var cutter = new Cutter(picAreaDom, {
    imgUrl: url, //图片链接
    conWidth: containerDom.offsetWidth, //容器宽度
    conHeight: containerDom.offsetWidth * 1.2, //容器高度
    speed: 2, //拖动速度
    callback: function() {
        //doSomething...
    }
});

这里有个地方要说明下,虽然 Cutter 中的 conWidth,conHeight 属性默认为 picAreaDom 的宽高,但如果 picAreaDom 的父级元素为 display:none,那么就获取不到 picAreaDom 尺寸(DEMO中单页应用机制导致的),这时候就需要显式传入裁剪区域的宽高。

callback 为初始化完成时的回调函数,保存实例化对象 cutter,用于之后的裁剪。

· 裁剪

var result = cutter.cut();
result 值即为裁剪后的 base64码。

最后一个小提示,如果需要重新上传图片裁剪,记得将容器中的 img 对象移除。具体的细节可以参考原码,整体比较简单。

h5图片裁切源码下载
精品好课
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
收藏
扫一扫关注我们