refactor: ♻️ Cropper组件支持支付宝小程序

This commit is contained in:
xuqingkai 2023-06-26 23:23:41 +08:00
parent 0b2df6e7b2
commit cd03fa292d
4 changed files with 121 additions and 49 deletions

View File

@ -1,3 +1,12 @@
<!--
* @Author: weisheng
* @Date: 2023-06-13 11:47:12
* @LastEditTime: 2023-06-26 23:22:26
* @LastEditors: weisheng
* @Description:
* @FilePath: \wot-design-uni\src\pages\imgCropper\Index.vue
* 记得注释
-->
<template> <template>
<demo-block title="基本用法" style="text-align: center"> <demo-block title="基本用法" style="text-align: center">
<wd-img-cropper <wd-img-cropper
@ -28,16 +37,10 @@ const show = ref<boolean>(false)
function upload() { function upload() {
uni.chooseImage({ uni.chooseImage({
count: 1, count: 1,
sizeType: ['original', 'compressed'], success: (res) => {
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0] const tempFilePaths = res.tempFilePaths[0]
src.value = tempFilePaths src.value = tempFilePaths
show.value = true show.value = true
// that.setData({
// show: true,
// src: tempFilePaths
// })
} }
}) })
} }

View File

@ -329,3 +329,20 @@ export function deepMerge(target = {}, source = {}) {
} }
return target return target
} }
/**
*
* @param path
* @param params
* @returns
*/
export function setUrlParams(path: string, params: Record<string, string>) {
for (const key in params) {
if (path.indexOf('?') > -1) {
path = path + `&${key}=${params[key]}`
} else {
path = path + `?${key}=${params[key]}`
}
}
return path
}

View File

@ -1,5 +1,5 @@
<template> <template>
<view @click="handleClick" :class="rootClass" :style="rootStyle"> <view @click="handleClick" data-eventsync="true" :class="rootClass" :style="rootStyle">
<image v-if="isImageUrl" class="wd-icon__image" :src="name"></image> <image v-if="isImageUrl" class="wd-icon__image" :src="name"></image>
</view> </view>
</template> </template>

View File

@ -1,4 +1,5 @@
<template> <template>
<!-- 绘制的图片canvas -->
<view id="wd-img-cropper" v-if="modelValue" :class="`wd-img-cropper ${customClass}`" @touchmove="preventTouchMove"> <view id="wd-img-cropper" v-if="modelValue" :class="`wd-img-cropper ${customClass}`" @touchmove="preventTouchMove">
<!-- 展示在用户面前的裁剪框 --> <!-- 展示在用户面前的裁剪框 -->
<view class="wd-img-cropper__wrapper"> <view class="wd-img-cropper__wrapper">
@ -32,11 +33,11 @@
</view> </view>
<!-- 展示的传过来的图片: 控制图片的旋转角度(rotate)缩放程度(imgScale)移动位置(translate) --> <!-- 展示的传过来的图片: 控制图片的旋转角度(rotate)缩放程度(imgScale)移动位置(translate) -->
<image <image
:prop="isAnimation"
:change:prop="animation ? animation.setAnimation : ''"
class="wd-img-cropper__img" class="wd-img-cropper__img"
:src="imgSrc" :src="imgSrc"
:style="`width: ${picWidth ? picWidth + 'px' : 'auto'}; height: ${picHeight ? picHeight + 'px' : 'auto'}; transform: translate(${ :style="imageStyle"
imgLeft - picWidth / 2
}px, ${imgTop - picHeight / 2}px) scale(${imgScale}) rotate(${imgAngle}deg); transition-duration:${isAnimation ? 0.4 : 0}s`"
:lazy-load="false" :lazy-load="false"
@touchstart="handleImgTouchStart" @touchstart="handleImgTouchStart"
@touchmove="handleImgTouchMove" @touchmove="handleImgTouchMove"
@ -48,13 +49,14 @@
<!-- 绘制的图片canvas --> <!-- 绘制的图片canvas -->
<canvas <canvas
canvas-id="wd-img-cropper-canvas" canvas-id="wd-img-cropper-canvas"
id="wd-img-cropper-canvas"
class="wd-img-cropper__canvas" class="wd-img-cropper__canvas"
disable-scroll="true" :disable-scroll="true"
:style="`width: ${Number(canvasWidth) * canvasScale}px; height: ${Number(canvasHeight) * canvasScale}px;`" :style="`width: ${Number(canvasWidth) * canvasScale}px; height: ${Number(canvasHeight) * canvasScale}px;`"
/> />
<!-- 下方按钮 --> <!-- 下方按钮 -->
<view class="wd-img-cropper__footer"> <view class="wd-img-cropper__footer">
<wd-icon v-if="!disabledRotate" name="rotate" size="24px" color="#fff" @click="handleRotate"></wd-icon> <wd-icon v-if="!disabledRotate" name="rotate" size="24px" color="#fff" data-eventsync="true" @click="handleRotate"></wd-icon>
<view class="wd-img-cropper__footer--button"> <view class="wd-img-cropper__footer--button">
<view class="is-cancel" @click="handleCancel">{{ cancelButtonText }}</view> <view class="is-cancel" @click="handleCancel">{{ cancelButtonText }}</view>
<wd-button size="small" :custom-style="buttonStyle" @click="handleConfirm">{{ confirmButtonText }}</wd-button> <wd-button size="small" :custom-style="buttonStyle" @click="handleConfirm">{{ confirmButtonText }}</wd-button>
@ -65,7 +67,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, getCurrentInstance, ref, watch } from 'vue' import { computed, getCurrentInstance, ref, watch } from 'vue'
import { objToStyle } from '../common/util' import { addUnit, objToStyle } from '../common/util'
// //
let CHANGE_TIME: any | null = null let CHANGE_TIME: any | null = null
@ -230,15 +232,15 @@ watch(
immediate: true immediate: true
} }
) )
watch( watch(
() => isAnimation.value, () => isAnimation.value,
(newValue) => { (newValue) => {
// 300 // 300
clearTimeout(CHANGE_TIME) CHANGE_TIME && clearTimeout(CHANGE_TIME)
if (newValue) { if (newValue) {
CHANGE_TIME = setTimeout(() => { CHANGE_TIME = setTimeout(() => {
isAnimation.value = false revertIsAnimation(false)
clearTimeout(CHANGE_TIME)
}, 300) }, 300)
} }
}, },
@ -261,15 +263,34 @@ const buttonStyle = computed(() => {
return objToStyle(style) return objToStyle(style)
}) })
const imageStyle = computed(() => {
const style: Record<string, string | number> = {
width: picWidth.value ? addUnit(picWidth.value) : 'auto',
height: picHeight.value ? addUnit(picHeight.value) : 'auto',
transform: `translate(${addUnit(imgLeft.value - picWidth.value / 2)}, ${addUnit(imgTop.value - picHeight.value / 2)}) scale(${
imgScale.value
}) rotate(${imgAngle.value}deg)`,
'transition-duration': (isAnimation.value ? 0.4 : 0) + 's'
}
return objToStyle(style)
})
const emit = defineEmits(['imgloaded', 'imgloaderror', 'cancel', 'confirm', 'update:modelValue']) const emit = defineEmits(['imgloaded', 'imgloaderror', 'cancel', 'confirm', 'update:modelValue'])
/**
* 逆转是否使用动画
*/
function revertIsAnimation(animation: boolean) {
isAnimation.value = animation
}
/** /**
* @description 对外暴露控制旋转角度 * @description 对外暴露控制旋转角度
* @param {Number} angle 角度 * @param {Number} angle 角度
*/ */
function setRoate(angle: number) { function setRoate(angle: number) {
if (!angle || props.disabledRotate) return if (!angle || props.disabledRotate) return
isAnimation.value = true revertIsAnimation(true)
imgAngle.value = angle imgAngle.value = angle
// //
detectImgPosIsEdge() detectImgPosIsEdge()
@ -382,28 +403,30 @@ function detectImgPosIsEdge(scale?: number) {
const currentScale = scale || imgScale.value const currentScale = scale || imgScale.value
let currentImgLeft = imgLeft.value let currentImgLeft = imgLeft.value
let currentImgTop = imgTop.value let currentImgTop = imgTop.value
let currentPicWidth = picWidth.value
let currentPicHeight = picHeight.value
// //
if ((currentScale / 90) % 2) { if ((imgAngle.value / 90) % 2) {
picWidth.value = picHeight.value currentPicWidth = picHeight.value
picHeight.value = picWidth.value currentPicHeight = picWidth.value
} }
// //
currentImgLeft = currentImgLeft =
(picWidth.value * currentScale) / 2 + cutLeft.value >= currentImgLeft ? currentImgLeft : (picWidth.value * imgScale.value) / 2 + cutLeft.value (currentPicWidth * currentScale) / 2 + cutLeft.value >= currentImgLeft ? currentImgLeft : (currentPicWidth * imgScale.value) / 2 + cutLeft.value
// //
currentImgLeft = currentImgLeft =
cutLeft.value + cutWidth.value - (picWidth.value * currentScale) / 2 <= currentImgLeft cutLeft.value + cutWidth.value - (currentPicWidth * currentScale) / 2 <= currentImgLeft
? currentImgLeft ? currentImgLeft
: cutLeft.value + cutWidth.value - (picWidth.value * currentScale) / 2 : cutLeft.value + cutWidth.value - (currentPicWidth * currentScale) / 2
// //
currentImgTop = currentImgTop =
(picHeight.value * currentScale) / 2 + cutTop.value >= currentImgTop ? currentImgTop : (picHeight.value * currentScale) / 2 + cutTop.value (currentPicHeight * currentScale) / 2 + cutTop.value >= currentImgTop ? currentImgTop : (currentPicHeight * currentScale) / 2 + cutTop.value
// //
currentImgTop = currentImgTop =
cutTop.value + cutHeight.value - (picHeight.value * currentScale) / 2 <= currentImgTop cutTop.value + cutHeight.value - (currentPicHeight * currentScale) / 2 <= currentImgTop
? currentImgTop ? currentImgTop
: cutTop.value + cutHeight.value - (picHeight.value * currentScale) / 2 : cutTop.value + cutHeight.value - (currentPicHeight * currentScale) / 2
imgScale.value = currentScale imgScale.value = currentScale
imgTop.value = currentImgTop imgTop.value = currentImgTop
@ -541,29 +564,32 @@ function handleConfirm(event) {
*/ */
function canvasToImage() { function canvasToImage() {
const { fileType, quality, exportScale } = props const { fileType, quality, exportScale } = props
uni.canvasToTempFilePath( try {
{ uni.canvasToTempFilePath(
width: cutWidth.value * exportScale, {
height: Math.round(cutHeight.value * exportScale), width: cutWidth.value * exportScale,
destWidth: cutWidth.value * exportScale, height: Math.round(cutHeight.value * exportScale),
destHeight: Math.round(cutHeight.value * exportScale), destWidth: cutWidth.value * exportScale,
fileType, destHeight: Math.round(cutHeight.value * exportScale),
quality, fileType,
canvasId: 'wd-img-cropper-canvas', quality,
success(res) { canvasId: 'wd-img-cropper-canvas',
emit('update:modelValue', false) success: (res) => {
emit('confirm', { emit('confirm', {
tempFilePath: res.tempFilePath, tempFilePath: res.tempFilePath,
width: cutWidth.value * exportScale, width: cutWidth.value * exportScale,
height: cutHeight.value * exportScale height: cutHeight.value * exportScale
}) })
},
complete: () => {
emit('update:modelValue', false)
}
}, },
fail() { proxy
emit('update:modelValue', false) )
} } catch (error) {
}, console.log(error)
proxy }
)
} }
/** /**
@ -587,6 +613,9 @@ function draw() {
} }
// drawImage xyx y // drawImage xyx y
ctx.value!.drawImage(props.imgSrc, -width / 2, -height / 2, width, height) ctx.value!.drawImage(props.imgSrc, -width / 2, -height / 2, width, height)
ctx.value!.restore()
// //
ctx.value!.draw(false, () => { ctx.value!.draw(false, () => {
canvasToImage() canvasToImage()
@ -598,8 +627,31 @@ function draw() {
draw() draw()
} }
function preventTouchMove() {} function preventTouchMove() {}
defineExpose({
revertIsAnimation
})
</script> </script>
<!-- #ifdef MP-WEIXIN || MP-QQ -->
<script module="animation" lang="wxs">
function setAnimation(newValue, oldValue, ownerInstance){
if (newValue) {
var id = ownerInstance.setTimeout(function() {
ownerInstance.callMethod('revertIsAnimation',false)
ownerInstance.clearTimeout(id)
},300)
}
}
module.exports= {
setAnimation:setAnimation,
}
</script>
<!-- #endif -->
<style lang="scss" scoped> <style lang="scss" scoped>
@import './index.scss'; @import './index.scss';
</style> </style>