Kros的博客 Kros的博客
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云

Kros

凡心所向,素履以往,生如逆旅,一苇以航
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云
  • 拼图小游戏

    • 拼图思路总览
    • 拆分图片
      • 拆分图片打乱顺序
      • 拖动拆分的图片
      • 拖动图片到原图上
      • 优化重构项目
      • 问题与总结
    • 井字棋

    • 贪吃蛇

    • 扫雷

    • 项目
    • 拼图小游戏
    kros
    2020-11-23

    拆分图片

    # 一、使用background-position模拟图片拆分

    使用background的background-position计算不同位置图片显示的位置。也就是说每个div都是一个完整的图片,通过计算来让图片进行位移同时搭配overflow: hidden就可以显示不同部位的图片,模拟切图。 代码如下:

    <template>
    	<div class="wrap">
    		<img :src="imgPath" style="width: 300px; height: 300px; margin: 0 20px;">
    		<div class="grid-base" :style="[girdStyle]">
    			<div class="puzzle-base" :style="[puzzleStyle]" v-for="(item, index) in size * size" :key="index">
    				<div class="puzzle-img" :style="[imgStyle(index)]"></div>
    			</div>
    		</div>
    	</div>
    </template>
    
    <script>
    	export default {
    		props: {
    			imgPath: {
    				type: String,
    				default: require('../assets/head.jpg')
    			},
    			size: {
    				type: Number,
    				default: 3
    			}
    		},
    		data(){
    			return {
    				width: 300,  //拼图图片的总宽,宽高一直
    				gap: 2,
    				tWidth: 300, // gird的总宽度
    			}
    		},
    		computed: {
    			girdStyle () {
    				return {		
    					width: this.tWidth + 'px',
    					height: this.tWidth + 'px',
    					'grid-row-gap': this.gap + 'px',
    					'grid-column-gap': this.gap + 'px',
    					'grid-template-columns': `repeat(${this.size}, ${this.pWidth}px)`,
    					'grid-template-rows': `repeat(${this.size}, ${this.pWidth}px)`
    				}
    			},
    			puzzleStyle () {
    				return {
    					width: this.pWidth + 'px',
    					height: this.pWidth + 'px',
    				}
    			},
    			imgStyle () {
    				return (index) => {
    					let x = -(index % 3) * this.width / this.size;
    					let y = -Math.floor(index / 3) * this.width / this.size;
    					return {
    						background: `url(${this.imgPath}) no-repeat ${x}px ${y}px/${this.width}px ${this.width}px`,
    						width: this.width + 'px',
    						height: this.width + 'px'
    					}
    				}
    			}
    		},
    		created() {
    			// 总宽 = (拼图一行个数 - 1) * 间隔 + 固定图片宽
    			this.tWidth = this.width + (this.size - 1) * this.gap;
    			this.pWidth = this.width / this.size;
    		}
    	}
    </script>
    
    <style lang="scss" scoped>
    	.wrap {
    		display: flex;
    		flex-direction: row;
    		align-items: center;		
    		.grid {			
    			display: grid;
    			.puzzle {
    				background-color: red;
    			}
    		}		
    		.grid-base {
    			display: grid;
    			opacity: .5;
    			.puzzle-base {
    				overflow: hidden;
    				.puzzle-img {
    				}
    			}
    		}
    	}
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89

    # 二、使用canvas真实拆分图片

    1. 首先把要切的图绘制到canvas上
    2. 每个切片图的x、y、width、height
    3. 使用getImageData获取截取该位置的imageData
    4. 使用putImageData把imageData再绘制到另一个canvas上
    5. 最后把该canvas的图像数据传递到img标签上即可
    6. 重复2~5步骤即可 代码如下:
    <template>
    	<div class="wrap">
    		<img :src="imgPath" id="img-base" style="width: 300px; height: 300px; margin: 0 20px;">
    		<div class="grid-base" :style="[girdStyle]">
    			<div class="puzzle-base" :style="[puzzleStyle]" v-for="(item, index) in size * size" :key="index">
    				<img class="puzzle-img" src="" alt="" :style="imgStyle">
    			</div>
    		</div>
    		<canvas id="imageFac" width="300" height="300" style="display: none;"></canvas>
    	</div>
    </template>
    
    <script>
    	export default {
    		props: {
    			imgPath: {
    				type: String,
    				default: require('../assets/head.jpg')
    			},
    			size: {
    				type: Number,
    				default: 3
    			}
    		},
    		data(){
    			return {
    				width: 300,  //拼图图片的总宽,宽高一直
    				gap: 2,
    				tWidth: 300, // gird的总宽度
    			}
    		},
    		computed: {
    			girdStyle () {
    				return {		
    					width: this.tWidth + 'px',
    					height: this.tWidth + 'px',
    					'grid-row-gap': this.gap + 'px',
    					'grid-column-gap': this.gap + 'px',
    					'grid-template-columns': `repeat(${this.size}, ${this.pWidth}px)`,
    					'grid-template-rows': `repeat(${this.size}, ${this.pWidth}px)`
    				}
    			},
    			puzzleStyle () {
    				return {
    					width: this.pWidth + 'px',
    					height: this.pWidth + 'px',
    				}
    			},
    			imgStyle () {
    				return {
    					width: this.pWidth + 'px',
    					height: this.pWidth + 'px',
    				}
    			}
    		},
    		created() {
    			// 总宽 = (拼图一行个数 - 1) * 间隔 + 固定图片宽
    			this.tWidth = this.width + (this.size - 1) * this.gap;
    			this.pWidth = this.width / this.size;
    		},
    		mounted() {
    			var canvas = document.getElementById('imageFac').getContext('2d');
    			var imgBase = document.getElementById('img-base');
    			// 获取图片的真实高度
    			var width = this.getImgWidth(imgBase.src);
    			canvas.drawImage(imgBase, 0, 0, width, width, 0, 0, 300, 300);
    			const imgs = document.getElementsByClassName('puzzle-img');
    			for(let y = 0; y < this.size; y++) {
    				for(let x = 0; x < this.size; x++) {
    					let imageData = canvas.getImageData(x * this.pWidth, y * this.pWidth, this.pWidth, this.pWidth);
    					var tempCanvas = document.createElement('canvas');
    					tempCanvas.width = this.pWidth;
    					tempCanvas.height = this.pWidth;
    					tempCanvas.fillStyle = 'white';
    					var tempCtx = tempCanvas.getContext('2d');
    					tempCtx.putImageData(imageData, 0, 0);
    					// 绘制图片
    					imgs[y * this.size + x].src = tempCanvas.toDataURL('image/jpeg');
    				}
    			}
    		},
    		methods: {
    			getImgWidth (imgSrc) {
    				var image = new Image();
    				image.src = imgSrc;
    				var naturalWidth = image.width;
    				return naturalWidth;
    			}
    		}
    	}
    </script>
    
    <style lang="scss" scoped="">
    	.wrap {
    		display: flex;
    		flex-direction: row;
    		align-items: center;
    		flex-wrap: wrap ;
    		
    		.grid {			
    			display: grid;
    			.puzzle {
    				background-color: red;
    			}
    		}
    		
    		.grid-base {
    			display: grid;
    			
    			.puzzle-base {
    				overflow: hidden;
    				.puzzle-img {
    				}
    			}
    		}
    	}
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117

    如下所示,两种方法实现的效果是一样的

    效果图

    上次更新: 2025/09/05, 8:09:00
    拼图思路总览
    拆分图片打乱顺序

    ← 拼图思路总览 拆分图片打乱顺序→

    最近更新
    01
    Find the next perfect square
    09-05
    02
    Regex validate PIN code
    09-05
    03
    Find the odd int
    09-05
    更多文章>
    Theme by Vdoing | Copyright © 2020-2025 kros king
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    icon-heart-o icon-heart icon-infinity icon-pause icon-play link next prev