自制一個H5圖片拖拽、裁剪插件(原生JS)


前言

如今的H5運營活動中,有很多都是讓用戶拍照或者上傳圖片,然后對照片加濾鏡、加貼紙、評顏值之類的。尤其是一些拍照軟件公司的運營活動幾乎全部都是這樣的。

博主也做過不少,為了省事就封裝了一個簡單的圖片拖拽、裁剪的插件。其實網上也有很多類似的插件,只不過有的功能冗余體積大,有的甚至還依賴jquery。索性自己搞一個輕量的,只是不支持縮放功能。

DEMO(手機上看效果比較好,PC上沒有兼容處理),原碼

 

實現

這里簡略說下實現過程,只截取部分代碼片段,有興趣的可以看下原碼,反正也很簡單。

圖片上傳

這個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 對象移除。具體的細節可以參考原碼,整體比較簡單。

 

感謝你的瀏覽,希望能有所幫助


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM