uniapp+vue写小程序页面,实现一张图片默认放大后,可以在容器内上下左右拖动查看
1.组件chargingimageViewer
<template><view class="image-view" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"><image:src="imageUrl"mode="aspectFill":style="{width: imageWidth + 'rpx',height: imageHeight + 'rpx',transform: `translate(${currentX}rpx, ${currentY}rpx)`,}"></image></view>
</template><script setup>import { ref, onMounted, computed } from 'vue';const props = defineProps({imageUrl: {type: String,required: true,},});// 视图容器尺寸const VIEW_WIDTH = 750; // 微信小程序设计稿宽度const VIEW_HEIGHT = 1800;// 缩放限制const MAX_SCALE = 5;const MIN_SCALE = ref(1);// 图片信息const imageWidth = ref(0);const imageHeight = ref(0);const originalWidth = ref(0);const originalHeight = ref(0);const scale = ref(1);const initialScale = ref(1);// 拖动状态const isDragging = ref(false);const isPinching = ref(false);const startX = ref(0);const startY = ref(0);const startDistance = ref(0);const currentX = ref(0);const currentY = ref(0);const lastX = ref(0);const lastY = ref(0);const pivotX = ref(0);const pivotY = ref(0);// 计算图片按比例放大后的尺寸const calculateImageSize = (width, height, scaleVal = 1.1) => {// 计算宽高比const ratio = width / height;// 优先满足高度,因为容器高度更大let newHeight = VIEW_HEIGHT;let newWidth = newHeight * ratio;// 如果宽度超出容器,则以宽度为基准if (newWidth < VIEW_WIDTH) {newWidth = VIEW_WIDTH;newHeight = newWidth / ratio;}// 应用缩放newWidth *= scaleVal;newHeight *= scaleVal;return {width: newWidth,height: newHeight,};};// 获取图片原始尺寸const getImageInfo = () => {uni.getImageInfo({src: props.imageUrl,success: (res) => {originalWidth.value = res.width;originalHeight.value = res.height;// 计算按比例放大后的图片尺寸const size = calculateImageSize(res.width, res.height);imageWidth.value = size.width;imageHeight.value = size.height;initialScale.value = size.width / res.width;// 设置最小缩放比例MIN_SCALE.value = initialScale.value;scale.value = initialScale.value;// 初始居中显示currentX.value = (VIEW_WIDTH - size.width) / 2;currentY.value = (VIEW_HEIGHT - size.height) / 2;lastX.value = currentX.value;lastY.value = currentY.value;},fail: (err) => {console.error('获取图片信息失败', err);},});};// 限制图片拖动边界const limitBounds = () => {// 计算可拖动范围const maxX = Math.max(0, (VIEW_WIDTH - imageWidth.value) / 2);const minX = Math.min(0, VIEW_WIDTH - imageWidth.value - maxX);const maxY = Math.max(0, (VIEW_HEIGHT - imageHeight.value) / 2);const minY = Math.min(0, VIEW_HEIGHT - imageHeight.value - maxY);// 限制X方向if (currentX.value > maxX) {currentX.value = maxX;} else if (currentX.value < minX) {currentX.value = minX;}// 限制Y方向if (currentY.value > maxY) {currentY.value = maxY;} else if (currentY.value < minY) {currentY.value = minY;}};// 更新图片尺寸和位置const updateImage = () => {const size = calculateImageSize(originalWidth.value, originalHeight.value, scale.value);imageWidth.value = size.width;imageHeight.value = size.height;// 调整位置以保持缩放中心不变if (isPinching.value) {currentX.value = pivotX.value - (pivotX.value - lastX.value) * (scale.value / lastScale.value);currentY.value = pivotY.value - (pivotY.value - lastY.value) * (scale.value / lastScale.value);}// 限制边界limitBounds();};let lastScale = 1;// 触摸事件处理const onTouchStart = (e) => {if (e.touches.length === 1) {// 单点触摸 - 拖动isDragging.value = true;isPinching.value = false;startX.value = e.touches[0].clientX;startY.value = e.touches[0].clientY;} else if (e.touches.length === 2) {// console.log(e.touches);// // 双点触摸 - 缩放// isDragging.value = false;// isPinching.value = true;// const touch1 = e.touches[0];// const touch2 = e.touches[1];// // 计算两点距离// const dx = touch2.clientX - touch1.clientX;// const dy = touch2.clientY - touch1.clientY;// startDistance.value = Math.sqrt(dx * dx + dy * dy);// // 计算缩放中心点// pivotX.value = (touch1.clientX + touch2.clientX) / 2;// pivotY.value = (touch1.clientY + touch2.clientY) / 2;// // 记录当前状态// lastScale = scale.value;// lastX.value = currentX.value;// lastY.value = currentY.value;}};const onTouchMove = (e) => {// 阻止事件冒泡和默认行为,防止页面滚动// e.stopPropagation()// e.preventDefault()if (isDragging.value && e.touches.length === 1) {// 处理拖动const clientX = e.touches[0].clientX;const clientY = e.touches[0].clientY;// 计算移动距离const deltaX = clientX - startX.value;const deltaY = clientY - startY.value;// 更新图片位置currentX.value = lastX.value + deltaX;currentY.value = lastY.value + deltaY;// 限制边界limitBounds();} else if (isPinching.value && e.touches.length === 2) {// // 处理缩放// const touch1 = e.touches[0];// const touch2 = e.touches[1];// // 计算两点距离// const dx = touch2.clientX - touch1.clientX;// const dy = touch2.clientY - touch1.clientY;// const distance = Math.sqrt(dx * dx + dy * dy);// // 计算缩放比例// const newScale = lastScale * (distance / startDistance.value);// // 限制缩放范围// if (newScale >= MIN_SCALE.value && newScale <= MAX_SCALE) {// scale.value = newScale;// updateImage();// }}};const onTouchEnd = () => {// 阻止事件冒泡,防止页面滚动// e.stopPropagation()isDragging.value = false;isPinching.value = false;lastX.value = currentX.value;lastY.value = currentY.value;};onMounted(() => {getImageInfo();});
</script><style scoped>.image-view {width: 750rpx;height: 1800rpx;overflow: hidden;position: relative;}image {position: absolute;transition: transform 0s;}
</style>
2.引用
<view class="mapbox"><chargingimageViewer :imageUrl="imageUrl"></chargingimageViewer></view>import chargingimageViewer from '@/components/chargingimageViewer/chargingimageViewer.vue';const imageUrl = ref('../../static/images/dingwei.png');