图片放大、缩小、恢复原比例、旋转vue
1.示图
支持点击下方按钮或者鼠标滚轮放大、缩小图片
2.代码
<template><div><divclass="canvas-container"ref="container"><canvasref="canvas"@wheel.prevent="handleWheel"@mousedown="startDrag"@mousemove="handleDrag"@mouseup="endDrag"@mouseleave="endDrag"></canvas></div><div class="image-tool"><el-tooltip:effect="'dark'":content="'放大'"placement="top"><div class="btn-img"><!-- 换成自己的图标路径 --><img:src="require('@/assets/images/plus.png')"alt=""@click="handleScale(1)"></div></el-tooltip><el-tooltip:effect="'dark'":content="'缩小'"placement="top"><div class="btn-img"><!-- 换成自己的图标路径 --><img:src="require('@/assets/images/decrease.png')"alt=""@click="handleScale(0)"></div></el-tooltip><el-tooltip:effect="'dark'":content="'100%比例'"placement="top"><div class="btn-img"><!-- 换成自己的图标路径 --><img:src="require('@/assets/images/1-1-img.png')"alt=""@click="handleZoom"></div></el-tooltip><el-tooltip:effect="'dark'":content="'旋转'"placement="top"><div class="btn-img"><!-- 换成自己的图标路径 --><img:src="require('@/assets/images/rotate.png')"alt=""@click="handleRotate"style="margin-left: -3px;"></div></el-tooltip></div></div>
</template><script>
export default {data () {return {// 照片路径filePath:'',// 比例scale: 1,scales: '',position: { x: 0, y: 0 },// 是否开始拖拽isDragging: false,lastPos: { x: 0, y: 0 },img: null,observer: null,// 旋转角度rotate: 0,ctx: ''}},mounted () {this.initCanvas()this.setupResizeObserver()// 监听浏览器窗口大小变化window.addEventListener('resize', this.handleResize)},beforeDestroy () {if (this.observer) this.observer.disconnect()window.removeEventListener('resize', this.handleResize)},methods: {/*** 初始化图片*/async initCanvas () {// this.filePath替换成自己的图片路径this.img = await this.loadImage(this.filePath)this.updateCanvasSize()this.drawImage()},/*** 图片预加载*/loadImage (src) {return new Promise((resolve) => {const img = new Image()img.onload = () => resolve(img)img.src = src})},updateCanvasSize () {const container = this.$refs.containerconst canvas = this.$refs.canvas// 设置canvas实际尺寸const dpr = window.devicePixelRatio || 1canvas.style.width = `${container.clientWidth}px`canvas.style.height = `${container.clientHeight}px`canvas.width = container.clientWidth * dprcanvas.height = container.clientHeight * dpr// 设置图片初始缩放比例const containerRatio = canvas.width / canvas.heightconst imageRatio = this.img.width / this.img.heightthis.scale = imageRatio > containerRatio? canvas.width / this.img.width: canvas.height / this.img.heightthis.scales = JSON.parse(JSON.stringify(this.scale))},/*** 绘制Canvas图像*/drawImage () {const canvas = this.$refs.canvasthis.ctx = canvas.getContext('2d')const dpr = window.devicePixelRatio || 1this.ctx.clearRect(0, 0, canvas.width, canvas.height)// 使用imageSmoothingEnabled禁用模糊处理this.ctx.imageSmoothingEnabled = falsethis.ctx.setTransform(dpr, 0, 0, dpr, 0, 0)const container = this.$refs.containerconst drawWidth = this.img.width * this.scaleconst drawHeight = this.img.height * this.scaleconst centerX = (container.clientWidth - drawWidth) / 2 + this.position.xconst centerY = (container.clientHeight - drawHeight) / 2 + this.position.y// 保存当前状态this.ctx.save()// 移动到图片中心this.ctx.translate(centerX + drawWidth / 2, centerY + drawHeight / 2)// 执行旋转this.ctx.rotate(this.rotate * Math.PI / 180)// 移回原点this.ctx.translate(-drawWidth / 2, -drawHeight / 2)this.ctx.drawImage(this.img,0, 0,drawWidth, drawHeight)// 恢复状态this.ctx.restore()},/*** 监听容器元素的大小变化并自动调整画布尺寸和重绘图像*/setupResizeObserver () {this.observer = new ResizeObserver(() => {this.updateCanvasSize()this.drawImage()})this.observer.observe(this.$refs.container)},handleResize () {this.updateCanvasSize()this.drawImage()},/*** 监听鼠标滚轮事件*/handleWheel (e) {const delta = e.deltaY > 0 ? -0.1 : 0.1this.scale = Math.max(0.1, this.scale + delta)this.drawImage()},/*** 鼠标按下时触发开始拖拽*/startDrag (e) {this.isDragging = truethis.lastPos = { x: e.clientX, y: e.clientY }},/*** 鼠标移动时处理拖拽逻辑*/handleDrag (e) {if (!this.isDragging) returnthis.position.x += e.clientX - this.lastPos.xthis.position.y += e.clientY - this.lastPos.ythis.lastPos = { x: e.clientX, y: e.clientY }this.drawImage()},/*** 鼠标释放或离开canvas区域时结束拖拽*/endDrag () {this.isDragging = false},/*** 图片的缩放* @param {*} zoom 缩放标识:zoom = 1 放大, zoom = 0 缩小*/handleScale (zoom) {if (zoom == 1) {this.scale += 0.1this.drawImage()} else {this.scale = Math.max(0.1, this.scale - 0.1)this.drawImage()}},/*** 1:1显示*/handleZoom () {this.scale = this.scalesthis.position = { x: 0, y: 0 }this.drawImage()},/*** 旋转*/handleRotate () {this.rotate = (this.rotate + 90) % 360this.drawImage()},/*** 重新加载图片(若有多张图片切换显示可使用,本实例暂未用到)*/refreshImage () {this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)//旋转角度this.rotate = 0this.scale = this.scalesthis.lastPos = { x: 0, y: 0 }this.position = { x: 0, y: 0 }this.img = nullthis.isDragging = falsethis.scales = ''this.scale = 1this.$nextTick(() => {this.initCanvas()})},}
}
</script><style scoped >
.canvas-container {position: relative;width: 100%;height: 100%;overflow: hidden;
}
canvas {display: block;cursor: grab;
}
canvas:active {cursor: grabbing;
}
.controls {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);display: flex;gap: 10px;
}
button {padding: 8px 16px;background: rgba(0, 0, 0, 0.7);color: white;border: none;border-radius: 4px;cursor: pointer;transition: all 0.2s;
}
button:hover {background: rgba(0, 0, 0, 0.9);
}
.image-tool {z-index: 3;height: 50px;display: flex;justify-content: center;align-items: center;
}
.image-tool .btn-img {margin: 0 12px;height: 30px;width: 30px;background-color: #f5f5f5;display: flex;justify-content: center;align-items: center;border-radius: 5px;cursor: pointer;
}
.image-tool .btn-img img {width: 20px;
}
</style>