99 <div class =" relative bg-elevated rounded-lg overflow-hidden" style =" max-height : 60vh ;" >
1010 <img ref =" imgRef" :src =" imageUrl" class =" max-w-full block" />
1111 </div >
12- <div class =" flex items-center justify-between " >
13- <div class =" flex gap-1" >
12+ <div class =" flex items-center gap-2 " >
13+ <div class =" flex gap-1 shrink-0 " >
1414 <UButton variant="outline" size="sm" icon="i-lucide-rotate-ccw" @click =" rotateLeft " >左旋</UButton >
1515 <UButton variant="outline" size="sm" icon="i-lucide-rotate-cw" @click =" rotateRight " >右旋</UButton >
1616 </div >
17- <div class =" flex gap-2" >
18- <UButton variant="ghost" @click =" cancel " >取消</UButton >
19- <UButton color="primary" icon="i-lucide-check" @click =" confirm " >确认裁剪</UButton >
20- </div >
17+ <input
18+ type =" range"
19+ :min =" -45"
20+ :max =" 45"
21+ step =" 0.5"
22+ v-model.number =" fineAngle"
23+ class =" flex-1 h-1.5 accent-[var(--ui-primary)]"
24+ @input =" onFineRotate"
25+ />
26+ <span class =" text-xs text-muted tabular-nums w-12 text-right shrink-0" >{{ fineAngle.toFixed(1) }}°</span >
27+ <UButton v-if =" fineAngle !== 0 " variant="ghost" size="xs" icon="i-lucide-undo-2" @click =" resetFine " />
28+ </div >
29+ <div class =" flex justify-end gap-2" >
30+ <UButton variant="ghost" @click =" cancel " >取消</UButton >
31+ <UButton color="primary" icon="i-lucide-check" @click =" confirm " >确认裁剪</UButton >
2132 </div >
2233 </div >
2334 </template >
@@ -39,12 +50,16 @@ const emit = defineEmits(['cropped', 'close'])
3950
4051const isOpen = ref (false )
4152const imgRef = ref (null )
53+ const fineAngle = ref (0 )
54+ const baseAngle = ref (0 )
4255let cropper = null
4356
4457watch (() => props .open , (val ) => { isOpen .value = val })
4558
4659watch (isOpen, (val ) => {
4760 if (val) {
61+ fineAngle .value = 0
62+ baseAngle .value = 0
4863 nextTick (() => initCropper ())
4964 } else {
5065 destroyCropper ()
@@ -165,8 +180,23 @@ function confirm() {
165180 }, ' image/jpeg' , 0.92 )
166181}
167182
168- function rotateLeft () { if (cropper) cropper .rotate (- 90 ) }
169- function rotateRight () { if (cropper) cropper .rotate (90 ) }
183+ function rotateLeft () {
184+ if (! cropper) return
185+ baseAngle .value -= 90
186+ cropper .rotateTo (baseAngle .value + fineAngle .value )
187+ }
188+ function rotateRight () {
189+ if (! cropper) return
190+ baseAngle .value += 90
191+ cropper .rotateTo (baseAngle .value + fineAngle .value )
192+ }
193+ function onFineRotate () {
194+ if (cropper) cropper .rotateTo (baseAngle .value + fineAngle .value )
195+ }
196+ function resetFine () {
197+ fineAngle .value = 0
198+ onFineRotate ()
199+ }
170200
171201function cancel () { isOpen .value = false }
172202
0 commit comments