前言
如今的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 對象移除。具體的細節可以參考原碼,整體比較簡單。
感謝你的瀏覽,希望能有所幫助