联调app
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
<template>
|
||||
<view class="preview-container">
|
||||
<!-- 右上角关闭按钮 -->
|
||||
<view class="close-btn" @click="close">
|
||||
<text class="close-icon">✕</text>
|
||||
<!-- 右上角按钮组 -->
|
||||
<view class="btn-group">
|
||||
<!-- 缩小按钮 -->
|
||||
<!-- <view class="btn zoom-out-btn" @click="zoomOut">
|
||||
<text class="btn-icon">−</text>
|
||||
</view> -->
|
||||
|
||||
<!-- 放大按钮 -->
|
||||
<!-- <view class="btn zoom-in-btn" @click="zoomIn">
|
||||
<text class="btn-icon">+</text>
|
||||
</view> -->
|
||||
|
||||
<!-- 下载按钮 -->
|
||||
<view class="btn download-btn" @click="downloadImage">
|
||||
<text class="btn-icon">⬇</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 下载按钮 -->
|
||||
<view class="download-btn" @click="downloadImage">
|
||||
<text class="download-icon">⬇️</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 图片预览区域,使用movable-area和movable-view实现缩放移动 -->
|
||||
<movable-area class="movable-area" :style="{ width: '100vw', height: '100vh' }">
|
||||
<movable-view
|
||||
@@ -19,21 +27,25 @@
|
||||
:scale-min="0.5"
|
||||
:scale-max="3"
|
||||
:scale-value="scaleValue"
|
||||
@scale="onScale"
|
||||
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd"
|
||||
:x="x"
|
||||
:y="y"
|
||||
:animation="true"
|
||||
:animation-duration="300"
|
||||
:style="{
|
||||
width: rotatedWidth + 'px',
|
||||
height: rotatedHeight + 'px'
|
||||
height: rotatedHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<view
|
||||
<view
|
||||
class="image-wrapper"
|
||||
:style="{
|
||||
width: imgWidth + 'px',
|
||||
height: imgHeight + 'px',
|
||||
transform: 'rotate(90deg)',
|
||||
transformOrigin: 'center center'
|
||||
transformOrigin: 'center center',
|
||||
}"
|
||||
>
|
||||
<image
|
||||
@@ -42,7 +54,7 @@
|
||||
mode="aspectFill"
|
||||
:style="{
|
||||
width: imgWidth + 'px',
|
||||
height: imgHeight + 'px'
|
||||
height: imgHeight + 'px',
|
||||
}"
|
||||
@load="onImageLoad"
|
||||
></image>
|
||||
@@ -50,10 +62,7 @@
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
|
||||
<!-- 图片信息提示 -->
|
||||
<view class="scale-tip" v-if="showScaleTip">
|
||||
当前缩放: {{ Math.round(scaleValue * 100) }}%
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -62,12 +71,12 @@ export default {
|
||||
onLoad(options) {
|
||||
this.imageUrl = decodeURIComponent(options.url) // 接收传递的图片URL,需要解码
|
||||
},
|
||||
|
||||
|
||||
data() {
|
||||
return {
|
||||
imageUrl: '',
|
||||
// 缩放相关
|
||||
scaleValue: 1,
|
||||
// 缩放相关 - 默认0.5
|
||||
scaleValue: 0.6,
|
||||
x: 0,
|
||||
y: 0,
|
||||
// 图片原始尺寸
|
||||
@@ -81,70 +90,132 @@ export default {
|
||||
tipTimer: null,
|
||||
// 屏幕尺寸
|
||||
windowWidth: 0,
|
||||
windowHeight: 0
|
||||
windowHeight: 0,
|
||||
// 缩放步长
|
||||
zoomStep: 0.2,
|
||||
// 动画控制
|
||||
isTouching: false,
|
||||
animationTimer: null
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
mounted() {
|
||||
// 获取屏幕尺寸
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
this.windowWidth = systemInfo.windowWidth;
|
||||
this.windowHeight = systemInfo.windowHeight;
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
this.windowWidth = systemInfo.windowWidth
|
||||
this.windowHeight = systemInfo.windowHeight
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
// 图片加载完成后获取尺寸
|
||||
onImageLoad(e) {
|
||||
const { width, height } = e.detail;
|
||||
|
||||
const { width, height } = e.detail
|
||||
|
||||
// 保存原始尺寸
|
||||
this.imgWidth = width;
|
||||
this.imgHeight = height;
|
||||
|
||||
this.imgWidth = width
|
||||
this.imgHeight = height
|
||||
|
||||
// 旋转90度后,宽度和高度互换
|
||||
this.rotatedWidth = height; // 旋转后宽度 = 原高度
|
||||
this.rotatedHeight = width; // 旋转后高度 = 原宽度
|
||||
|
||||
// 计算初始位置居中
|
||||
this.resetPosition();
|
||||
|
||||
console.log('图片加载:', {width, height}, '旋转后:', {rotatedWidth: this.rotatedWidth, rotatedHeight: this.rotatedHeight});
|
||||
this.rotatedWidth = height // 旋转后宽度 = 原高度
|
||||
this.rotatedHeight = width // 旋转后高度 = 原宽度
|
||||
|
||||
// 计算初始位置居中(考虑0.5缩放)
|
||||
this.resetPosition()
|
||||
},
|
||||
|
||||
// 重置位置到中心
|
||||
|
||||
// 重置位置到中心(考虑当前缩放比例)
|
||||
resetPosition() {
|
||||
// 计算居中的偏移量
|
||||
this.x = (this.windowWidth - this.rotatedWidth) / 2;
|
||||
this.y = (this.windowHeight - this.rotatedHeight) / 2;
|
||||
|
||||
console.log('重置位置:', {x: this.x, y: this.y, windowWidth: this.windowWidth, windowHeight: this.windowHeight});
|
||||
// 计算居中的偏移量,考虑缩放比例
|
||||
const displayWidth = this.rotatedWidth * this.scaleValue
|
||||
const displayHeight = this.rotatedHeight * this.scaleValue
|
||||
|
||||
this.x = (this.windowWidth - displayWidth) / 2
|
||||
this.y = (this.windowHeight - displayHeight) / 2
|
||||
},
|
||||
|
||||
|
||||
// 触摸开始
|
||||
onTouchStart() {
|
||||
this.isTouching = true
|
||||
},
|
||||
|
||||
// 触摸结束
|
||||
onTouchEnd() {
|
||||
this.isTouching = false
|
||||
},
|
||||
|
||||
// 缩放事件处理
|
||||
onScale(e) {
|
||||
this.scaleValue = e.detail.scale;
|
||||
|
||||
this.scaleValue = e.detail.scale
|
||||
|
||||
// 显示缩放提示
|
||||
this.showScaleTip = true;
|
||||
this.showScaleTip = true
|
||||
if (this.tipTimer) {
|
||||
clearTimeout(this.tipTimer);
|
||||
clearTimeout(this.tipTimer)
|
||||
}
|
||||
this.tipTimer = setTimeout(() => {
|
||||
this.showScaleTip = false;
|
||||
}, 1500);
|
||||
this.showScaleTip = false
|
||||
}, 1500)
|
||||
},
|
||||
|
||||
// 关闭预览
|
||||
close() {
|
||||
uni.navigateBack();
|
||||
|
||||
// 放大
|
||||
zoomIn() {
|
||||
// 计算新的缩放值,不超过最大值
|
||||
const newScale = Math.min(this.scaleValue + this.zoomStep, 3)
|
||||
this.setScaleWithAnimation(newScale)
|
||||
},
|
||||
|
||||
|
||||
// 缩小
|
||||
zoomOut() {
|
||||
// 计算新的缩放值,不低于最小值
|
||||
const newScale = Math.max(this.scaleValue - this.zoomStep, 0.5)
|
||||
this.setScaleWithAnimation(newScale)
|
||||
},
|
||||
|
||||
// 带动画的设置缩放值
|
||||
setScaleWithAnimation(newScale) {
|
||||
// 保存旧的缩放值用于动画
|
||||
const oldScale = this.scaleValue
|
||||
|
||||
// 计算缩放中心点(屏幕中心)
|
||||
const centerX = this.windowWidth / 2
|
||||
const centerY = this.windowHeight / 2
|
||||
|
||||
// 计算当前图片中心点
|
||||
const oldDisplayWidth = this.rotatedWidth * oldScale
|
||||
const oldDisplayHeight = this.rotatedHeight * oldScale
|
||||
const oldCenterX = this.x + oldDisplayWidth / 2
|
||||
const oldCenterY = this.y + oldDisplayHeight / 2
|
||||
|
||||
// 计算偏移量,使缩放后图片中心保持在屏幕中心
|
||||
const newDisplayWidth = this.rotatedWidth * newScale
|
||||
const newDisplayHeight = this.rotatedHeight * newScale
|
||||
const newX = centerX - newDisplayWidth / 2
|
||||
const newY = centerY - newDisplayHeight / 2
|
||||
|
||||
// 更新缩放值和位置
|
||||
this.scaleValue = newScale
|
||||
this.x = newX
|
||||
this.y = newY
|
||||
|
||||
// 显示缩放提示
|
||||
this.showScaleTip = true
|
||||
if (this.tipTimer) {
|
||||
clearTimeout(this.tipTimer)
|
||||
}
|
||||
this.tipTimer = setTimeout(() => {
|
||||
this.showScaleTip = false
|
||||
}, 1500)
|
||||
|
||||
console.log('缩放:', {oldScale, newScale, x: this.x, y: this.y})
|
||||
},
|
||||
|
||||
// 下载图片
|
||||
downloadImage() {
|
||||
uni.showLoading({
|
||||
title: '下载中...'
|
||||
});
|
||||
|
||||
title: '下载中,请稍等...',
|
||||
mask: true,
|
||||
})
|
||||
|
||||
// 先获取图片信息(如果是网络图片需要先下载)
|
||||
uni.downloadFile({
|
||||
url: this.imageUrl,
|
||||
@@ -154,16 +225,16 @@ export default {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
icon: 'success',
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('保存失败', err);
|
||||
|
||||
uni.hideLoading()
|
||||
console.error('保存失败', err)
|
||||
|
||||
// 处理用户拒绝权限的情况
|
||||
if (err.errMsg.includes('auth deny')) {
|
||||
uni.showModal({
|
||||
@@ -173,52 +244,49 @@ export default {
|
||||
if (res.confirm) {
|
||||
uni.openSetting({
|
||||
success: (settingRes) => {
|
||||
console.log('打开设置页面', settingRes);
|
||||
}
|
||||
});
|
||||
console.log('打开设置页面', settingRes)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
})
|
||||
} else {
|
||||
uni.hideLoading();
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '下载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('下载失败', err);
|
||||
uni.hideLoading()
|
||||
console.error('下载失败', err)
|
||||
uni.showToast({
|
||||
title: '下载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
icon: 'none',
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
// 双击重置缩放和位置(可选功能)
|
||||
onDoubleTap() {
|
||||
this.scaleValue = 1;
|
||||
this.resetPosition();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 页面返回前清理定时器
|
||||
onUnload() {
|
||||
if (this.tipTimer) {
|
||||
clearTimeout(this.tipTimer);
|
||||
clearTimeout(this.tipTimer)
|
||||
}
|
||||
}
|
||||
if (this.animationTimer) {
|
||||
cancelAnimationFrame(this.animationTimer)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -241,62 +309,89 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// 添加硬件加速
|
||||
transform: translateZ(0);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform 0.1s ease;
|
||||
// 添加硬件加速
|
||||
transform: translateZ(0) rotate(90deg);
|
||||
will-change: transform;
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
|
||||
.preview-img {
|
||||
display: block;
|
||||
// 添加硬件加速
|
||||
transform: translateZ(0);
|
||||
will-change: transform;
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
// 关闭按钮
|
||||
.close-btn {
|
||||
// 按钮组
|
||||
.btn-group {
|
||||
position: fixed;
|
||||
top: 30rpx;
|
||||
right: 30rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20rpx;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
// 通用按钮样式
|
||||
.btn {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
// 按钮不参与动画
|
||||
transform: translateZ(0);
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
.close-icon {
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// 缩小按钮
|
||||
.zoom-out-btn {
|
||||
.btn-icon {
|
||||
font-size: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 放大按钮
|
||||
.zoom-in-btn {
|
||||
.btn-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 下载按钮
|
||||
.download-btn {
|
||||
position: fixed;
|
||||
top: 30rpx;
|
||||
right: 110rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
|
||||
.download-icon {
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
line-height: 1;
|
||||
.btn-icon {
|
||||
font-size: 35rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +400,7 @@ export default {
|
||||
position: fixed;
|
||||
bottom: 100rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transform: translateX(-50%) translateZ(0);
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
padding: 10rpx 30rpx;
|
||||
@@ -315,12 +410,22 @@ export default {
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
animation: fadeInOut 1.5s ease;
|
||||
// 提示不参与动画
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
@keyframes fadeInOut {
|
||||
0% { opacity: 0; }
|
||||
15% { opacity: 1; }
|
||||
85% { opacity: 1; }
|
||||
100% { opacity: 0; }
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
15% {
|
||||
opacity: 1;
|
||||
}
|
||||
85% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user