wxml
<view class="wx-content-info" wx:if="{{imageSrc}}">
<view wx:if="{{isShowImg}}" class="wx-corpper" style="width:{{cropperInitW}}rpx;height:{{cropperInitH}}rpx;background:#000">
<view class="wx-corpper-content" style="width:{{cropperW}}rpx;height:{{cropperH}}rpx;left:{{cropperL}}rpx;top:{{cropperT}}rpx">
<image src="{{imageSrc}}" style="width:{{cropperW}}rpx;height:{{cropperH}}rpx"></image>
<view class="wx-corpper-crop-box" bindtouchstart="contentStartMove" bindtouchmove="contentMoveing" style="width:{{cutW}}rpx;height:{{cutH}}rpx;left:{{cutL}}rpx;top:{{cutT}}rpx">
<view class="wx-cropper-view-box">
<view class="wx-cropper-dashed-h"></view>
<view class="wx-cropper-dashed-v"></view>
<view class="wx-cropper-line-t" data-drag="top" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-line-r" data-drag="right" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-line-b" data-drag="bottom" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-line-l" data-drag="left" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-t" data-drag="top" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-tr" data-drag="topTight"></view>
<view class="wx-cropper-point point-r" data-drag="right" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-rb" data-drag="rightBottom" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-b" data-drag="bottom" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-bl" data-drag="bottomLeft"></view>
<view class="wx-cropper-point point-l" data-drag="left" catchtouchstart="dragStart" catchtouchmove="dragMove"></view>
<view class="wx-cropper-point point-lt" data-drag="leftTop"></view>
</view>
</view>
</view>
</view>
<canvas canvas-id="myCanvas" style="position:absolute;border: 1px solid red; width:{{imageW}}rpx;height:{{imageH}}rpx;top:-9999px;left:-9999px;"></canvas>
<view style="text-align: center;"><image style="width: 192rpx;height: 192rpx;border-radius: 500rpx !important;overflow: hidden; margin-top: 30rpx;margin-bottom: 30rpx;" src="{{returnImage}}"></image></view>
<view style="display: flex;">
<button type="primary" bindtap="getImageInfo">头像预览</button>
<button type="primary" bindtap="upload" loading="{{isdisabled}}" disabled="{{isdisabled}}">上传头像</button>
</view>
</view>
js
const app = getApp();
// 手机的宽度
var windowWRPX = 750
// 拖动时候的 pageX
var pageX = 0
// 拖动时候的 pageY
var pageY = 0
var pixelRatio = wx.getSystemInfoSync().pixelRatio
// 调整大小时候的 pageX
var sizeConfPageX = 0
// 调整大小时候的 pageY
var sizeConfPageY = 0
var initDragCutW = 0
var initDragCutL = 0
var initDragCutH = 0
var initDragCutT = 0
// 移动时 手势位移与 实际元素位移的比
var dragScaleP = 2
Page({
/**
* 页面的初始数据
*/
data: {
topLabel: '头像上传', //顶部栏input
isIphoneX: app.globalStore.globalData.isIphoneX, //是否Iphonx
windowHeight: app.globalStore.globalData.windowHeight,
windowWidth: app.globalStore.globalData.windowWidth,
triggered: false, //模块是否刷新中
isdisabled: false, //是否提交
showmodel: false, //是否编辑模式
imageSrc: '',
returnImage: '',
isShowImg: false,
// 初始化的宽高
cropperInitW: windowWRPX,
cropperInitH: windowWRPX,
// 动态的宽高
cropperW: windowWRPX,
cropperH: windowWRPX,
// 动态的left top值
cropperL: 0,
cropperT: 0,
// 图片缩放值
scaleP: 0,
imageW: 0,
imageH: 0,
// 裁剪框 宽高
cutW: 0,
cutH: 0,
cutL: 0,
cutT: 0,
},
upload(e) { //头像上传
wx.showLoading({
title: '头像上传中...',
})
this.setData({isdisabled:true})
const userinfo = wx.getStorageSync('userinfo')
let encryptor = new Encrypt.JSEncrypt()
encryptor.setPublicKey(publicKey);
let requestkey = encryptor.encrypt(userinfo.YHBH + ',' + userinfo.OPENID + ',' + userinfo.BH + ',' + new Date().getTime()) // 加密
// 将图片写入画布
const ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(this.data.imageSrc)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题
let canvasW = (this.data.cutW / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasH = (this.data.cutH / this.data.cropperH) * (this.data.imageH / pixelRatio)
let canvasL = (this.data.cutL / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasT = (this.data.cutT / this.data.cropperH) * (this.data.imageH / pixelRatio)
setTimeout(() => {
wx.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW * 0.35,//设置压缩百分比,如果写100就是分辨率
destHeight: canvasH * 0.35,//设置压缩百分比,如果写100就是分辨率
canvasId: 'myCanvas',
fileType: 'jpg',
success: res => {
wx.uploadFile({
url: App.uploads + '/weixin/upload/img/upload/cover',
filePath: res.tempFilePath,
name: 'file',
header: {
token: requestkey
},
formData: {
BH: wx.getStorageSync('userinfo').BH
},
success:res=>{
res.data = JSON.parse(res.data)
let pages = getCurrentPages();
let previousPage = pages[pages.length - 2]; //上一个页面
previousPage.setData({
avatarUrl: res.data.data.filePath
})
const userinfo = wx.getStorageSync('userinfo')
userinfo.TX = res.data.data.filePath
wx.setStorageSync('userinfo', userinfo)
wx.hideLoading()
wx.showToast({
title: '上传成功',
icon: "succes",
duration: 1500
})
this.setData({isdisabled:false})
},
fail:res=>{
this.setData({isdisabled:false})
wx.hideLoading()
wx.showToast({
title: '上传失败',
icon: "error",
duration: 1500
})
}
})
}
})
}, 500);
})
},
// 拖动时候触发的touchStart事件
contentStartMove(e) {
pageX = e.touches[0].pageX
pageY = e.touches[0].pageY
},
// 拖动时候触发的touchMove事件
contentMoveing(e) {
// this.data.cutL + (e.touches[0].pageX - pageX)
// console.log(e.touches[0].pageX)
// console.log(e.touches[0].pageX - pageX)
var dragLengthX = (pageX - e.touches[0].pageX) * dragScaleP
var dragLengthY = (pageY - e.touches[0].pageY) * dragScaleP
var minX = Math.max(this.data.cutL - (dragLengthX), 0)
var minY = Math.max(this.data.cutT - (dragLengthY), 0)
var maxX = this.data.cropperW - this.data.cutW
var maxY = this.data.cropperH - this.data.cutH
this.setData({
cutL: Math.min(maxX, minX),
cutT: Math.min(maxY, minY),
})
// console.log(`${maxX} ----- ${minX}`)
pageX = e.touches[0].pageX
pageY = e.touches[0].pageY
},
// 获取图片
getImageInfo() {
wx.showLoading({
title: '图片生成中...',
})
wx.downloadFile({
url: this.data.imageSrc, //仅为示例,并非真实的资源
success: res=>{
// 将图片写入画布
const ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(res.tempFilePath)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题
let canvasW = (this.data.cutW / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasH = (this.data.cutH / this.data.cropperH) * (this.data.imageH / pixelRatio)
let canvasL = (this.data.cutL / this.data.cropperW) * (this.data.imageW / pixelRatio)
let canvasT = (this.data.cutT / this.data.cropperH) * (this.data.imageH / pixelRatio)
setTimeout(() => {
wx.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW * 0.35,//设置压缩百分比,如果写100就是分辨率
destHeight: canvasH * 0.35,//设置压缩百分比,如果写100就是分辨率
canvasId: 'myCanvas',
fileType: 'jpg',
success: res=>{
wx.hideLoading()
// wx.getImageInfo({
// src: res.tempFilePath,
// success (res) {
// console.log(res.width)//图片宽
// console.log(res.height)//图片高
// }
// })
// 成功获得地址的地方
wx.previewImage({
current: '', // 当前显示图片的http链接
urls: [res.tempFilePath] // 需要预览的图片http链接列表
})
this.setData({
returnImage:res.tempFilePath
})
}
})
}, 200);
})
}
})
},
// 设置大小的时候触发的touchStart事件
dragStart(e) {
sizeConfPageX = e.touches[0].pageX
sizeConfPageY = e.touches[0].pageY
initDragCutW = this.data.cutW
initDragCutL = this.data.cutL
initDragCutT = this.data.cutT
initDragCutH = this.data.cutH
},
// 设置大小的时候触发的touchMove事件
dragMove(e) {
var dragType = e.target.dataset.drag
switch (dragType) {
case 'right':
var dragLength = (sizeConfPageX - e.touches[0].pageX) * dragScaleP
if (initDragCutW >= dragLength) {
// 如果 移动小于0 说明是在往下啦 放大裁剪的高度 这样一来 图片的高度 最大 等于 图片的top值加 当前图片的高度 否则就说明超出界限
if (dragLength < 0 && this.data.cropperW > initDragCutL + this.data.cutW) {
this.setData({
cutW: initDragCutW - dragLength
})
}
// 如果是移动 大于0 说明在缩小 只需要缩小的距离小于原本裁剪的高度就ok
if (dragLength > 0) {
this.setData({
cutW: initDragCutW - dragLength
})
} else {
return
}
} else {
return
}
break;
case 'left':
var dragLength = (dragLength = sizeConfPageX - e.touches[0].pageX) * dragScaleP
console.log(dragLength)
if (initDragCutW >= dragLength && initDragCutL > dragLength) {
if (dragLength < 0 && Math.abs(dragLength) >= initDragCutW) return
this.setData({
cutL: initDragCutL - dragLength,
cutW: initDragCutW + dragLength
})
} else {
return;
}
break;
case 'top':
var dragLength = (sizeConfPageY - e.touches[0].pageY) * dragScaleP
if (initDragCutH >= dragLength && initDragCutT > dragLength) {
if (dragLength < 0 && Math.abs(dragLength) >= initDragCutH) return
this.setData({
cutT: initDragCutT - dragLength,
cutH: initDragCutH + dragLength
})
} else {
return;
}
break;
case 'bottom':
var dragLength = (sizeConfPageY - e.touches[0].pageY) * dragScaleP
// console.log(this.data.cropperH > this.data.cutT + this.data.cutH)
// console.log(dragLength)
// console.log(initDragCutH >= dragLength)
// console.log(this.data.cropperH > initDragCutT + this.data.cutH)
// 必须是 dragLength 向上缩小的时候必须小于原本的高度
if (initDragCutH >= dragLength) {
// 如果 移动小于0 说明是在往下啦 放大裁剪的高度 这样一来 图片的高度 最大 等于 图片的top值加 当前图片的高度 否则就说明超出界限
if (dragLength < 0 && this.data.cropperH > initDragCutT + this.data.cutH) {
this.setData({
cutH: initDragCutH - dragLength
})
}
// 如果是移动 大于0 说明在缩小 只需要缩小的距离小于原本裁剪的高度就ok
if (dragLength > 0) {
this.setData({
cutH: initDragCutH - dragLength
})
} else {
return
}
} else {
return
}
break;
case 'rightBottom':
var dragLengthX = (sizeConfPageX - e.touches[0].pageX) * dragScaleP
var dragLengthY = (sizeConfPageY - e.touches[0].pageY) * dragScaleP
if (initDragCutH >= dragLengthY && initDragCutW >= dragLengthX) {
// bottom 方向的变化
if ((dragLengthY < 0 && this.data.cropperH > initDragCutT + this.data.cutH) || (dragLengthY > 0)) {
this.setData({
cutH: initDragCutH - dragLengthY
})
}
// right 方向的变化
if ((dragLengthX < 0 && this.data.cropperW > initDragCutL + this.data.cutW) || (dragLengthX > 0)) {
this.setData({
cutW: initDragCutW - dragLengthX
})
} else {
return
}
} else {
return
}
break;
default:
break;
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData({
imageSrc: 'https://wx3.sinaimg.cn/orj360/6b03f0e6gy1h6c1mivf4lj20u01400wu.jpg'
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
wx.showLoading({
title: '图片加载中...',
})
wx.getImageInfo({
src: this.data.imageSrc,
success: res=>{
var innerAspectRadio = res.width / res.height;
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
if (innerAspectRadio >= 1) {
this.setData({
cropperW: windowWRPX,
cropperH: windowWRPX / innerAspectRadio,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX / innerAspectRadio) / 2),
// 裁剪框 宽高
cutW: windowWRPX - 200,
cutH: windowWRPX / innerAspectRadio - 200,
cutL: Math.ceil((windowWRPX - windowWRPX + 200) / 2),
cutT: Math.ceil((windowWRPX / innerAspectRadio - (windowWRPX / innerAspectRadio - 200)) / 2),
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
} else {
this.setData({
cropperW: windowWRPX * innerAspectRadio,
cropperH: windowWRPX,
// 初始化left right
cropperL: Math.ceil((windowWRPX - windowWRPX * innerAspectRadio) / 2),
cropperT: Math.ceil((windowWRPX - windowWRPX) / 2),
// 裁剪框的宽高
cutW: windowWRPX * innerAspectRadio - 200,
cutH: 200,
cutL: Math.ceil((windowWRPX * innerAspectRadio - (windowWRPX * innerAspectRadio - 50)) / 2),
cutT: Math.ceil((windowWRPX - 200) / 2),
// 图片缩放值
scaleP: res.width * pixelRatio / windowWRPX,
// 图片原始宽度 rpx
imageW: res.width * pixelRatio,
imageH: res.height * pixelRatio
})
}
this.setData({
isShowImg: true
})
wx.hideLoading()
}
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
css
.wx-corpper{
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
box-sizing: border-box;
}
.wx-corpper-content{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.wx-corpper-content image {
display: block;
width: 100%;
min-width: 0 !important;
max-width: none !important;
height: 100%;
min-height: 0 !important;
max-height: none !important;
image-orientation: 0deg !important;
margin: 0 auto;
}
/* 移动图片效果 */
.wx-cropper-drag-box{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: move;
background: rgba(0,0,0,0.6);
z-index: 1;
}
/* 内部的信息 */
.wx-corpper-crop-box{
position: absolute;
width: 500rpx;
height: 500rpx;
background: rgba(255,255,255,0.3);
z-index: 2;
}
.wx-corpper-crop-box .wx-cropper-view-box {
position: relative;
display: block;
width: 100%;
height: 100%;
overflow: visible;
outline: 1px solid #69f;
outline-color: rgba(102, 153, 255, .75)
}
/* 横向虚线 */
.wx-cropper-dashed-h{
position: absolute;
top: 33.33333333%;
left: 0;
width: 100%;
height: 33.33333333%;
border-top: 1px dashed rgba(255,255,255,0.5);
border-bottom: 1px dashed rgba(255,255,255,0.5);
}
/* 纵向虚线 */
.wx-cropper-dashed-v{
position: absolute;
left: 33.33333333%;
top: 0;
width: 33.33333333%;
height: 100%;
border-left: 1px dashed rgba(255,255,255,0.5);
border-right: 1px dashed rgba(255,255,255,0.5);
}
/* 四个方向的线 为了之后的拖动事件*/
.wx-cropper-line-t{
position: absolute;
display: block;
width: 100%;
background-color: #69f;
top: 0;
left: 0;
height: 1px;
opacity: 0.1;
cursor: n-resize;
}
.wx-cropper-line-t::before{
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0,-50%,0);
transform: translate3d(0,-50%,0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.wx-cropper-line-r{
position: absolute;
display: block;
background-color: #69f;
top: 0;
right: 0px;
width: 1px;
opacity: 0.1;
height: 100%;
cursor: e-resize;
}
.wx-cropper-line-r::before{
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%,0,0);
transform: translate3d(-50%,0,0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.wx-cropper-line-b{
position: absolute;
display: block;
width: 100%;
background-color: #69f;
bottom: 0;
left: 0;
height: 1px;
opacity: 0.1;
cursor: s-resize;
}
.wx-cropper-line-b::before{
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0,-50%,0);
transform: translate3d(0,-50%,0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.wx-cropper-line-l{
position: absolute;
display: block;
background-color: #69f;
top: 0;
left: 0;
width: 1px;
opacity: 0.1;
height: 100%;
cursor: w-resize;
}
.wx-cropper-line-l::before{
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%,0,0);
transform: translate3d(-50%,0,0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.wx-cropper-point{
width: 5px;
height: 5px;
background-color: #69f;
opacity: .75;
position: absolute;
z-index: 3;
}
.point-t{
top: -3px;
left: 50%;
margin-left: -3px;
cursor: n-resize;
}
.point-tr{
top: -3px;
left: 100%;
margin-left: -3px;
cursor: n-resize;
}
.point-r{
top: 50%;
left:100%;
margin-left: -3px;
margin-top: -3px;
cursor: n-resize;
}
.point-rb{
left: 100%;
top: 100%;
-webkit-transform: translate3d(-50%,-50%,0);
transform: translate3d(-50%,-50%,0);
cursor: n-resize;
width: 24rpx;
height: 24rpx;
background-color: #69f;
position: absolute;
z-index: 1112;
opacity: 1;
}
.point-b{
left:50%;
top: 100%;
margin-left: -3px;
margin-top: -3px;
cursor: n-resize;
}
.point-bl{
left:0%;
top: 100%;
margin-left: -3px;
margin-top: -3px;
cursor: n-resize;
}
.point-l{
left:0%;
top: 50%;
margin-left: -3px;
margin-top: -3px;
cursor: n-resize;
}
.point-lt{
left:0%;
top: 0%;
margin-left: -3px;
margin-top: -3px;
cursor: n-resize;
}
/* 裁剪框预览内容 */
.wx-cropper-viewer{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.wx-cropper-viewer image{
position: absolute;
z-index: 2;
}