本实验前期准备:
①下载HBuilderX
②新建uniapp项目,选择默认模板,Vue版本选择2
③在HBuilderX工具栏中点击“插件安装”,前往uniapp插件市场安装uViewUI(选择使用HbuilderX导入插件)
④点击该链接学习配置uView
(③④步骤非必要,如果要使用uViewUI组件可以尝试)
效果展示
页面结构
<template>
<view>
<view class="btnBox">
<!-- u-button 为uViewUI组件 -->
<u-button text="添加图片" @click="selectImage"></u-button>
</view>
<!-- 创建一个画布,绑定触摸动作开始、触摸后移动、触摸动作结束事件 -->
<canvas
canvas-id="myCanvas"
id="myCanvas"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
></canvas>
</view>
</template>
<style>
/* 设置画布大小 */
#myCanvas{
width: 750rpx;
height: 900rpx;
}
</style>
数据结构
layers数组中的每一组数据可以看作是一个图层,下标越往后图层层级越高。
export default {
data(){
return{
ctx:'', //canvas上下文对象
beginX:'',
beginY:'',
movedX:'',
movedY:'',
layers:[], //存储图片对象
}
},
onLoad() {
this.ctx = uni.createCanvasContext('myCanvas')
},
methods:{...}
....
}
选择并绘制图片
点击“添加图片”按钮时触发一下方法
darwImages(url,x,y,w,h){
this.ctx.drawImage(url,x,y,w,h)
this.ctx.draw(true)
},
layer(x,y)为图像的左上角在画布 X 轴和Y轴的位置
layer(w,h)为图像在画布中的宽高大小
layer.isDrag为当前图片是否为被拖拽对象,默认为false
selectImage(){
uni.chooseImage({
success:(res)=> {
// 图片对象
let layer = {
type:'photo',
resoure:res.tempFilePaths[0],
x:0,
y:0,
w:200,
h:150,
isDrag:false
}
// 将图片对象添加到layers数组中
this.layers.push(layer)
// 将图片绘制到画布中
this.darwImages(res.tempFilePaths[0],layer.x,layer.y,layer.w,layer.h)
}
})
},
拖拽图片
拖拽图片有三个动作:一是选中图片,二是长按移动图片,三是结束移动图片。
在选中图片这一步骤中有几个要点:
①如何判断我们选中了图片?
②当触摸的点落在了两张图片重合的地方,如何将最上层的图片设置为我们要选中并拖拽的对象?
解①:
根据上图我们可以得出:只要同时满足 x > img.x ,y > img.y , x < img.w + img.x , y < img.h + img.y 四个条件,就可以断定选中了图片。同时修改isDrag属性为true,并将当前选中的图片的层级设置为最高。
解②:
在前面我已介绍过,layers数组中下标越往后图层层级越高(因为canvas默认新绘制的图片会覆盖先绘制的图片),因此我们只需要反向遍历layers,优先判断图层层级较高的图片是否被选中即可。
handleTouchStart(e){
let {x,y} = e.changedTouches[0]
this.beginX = x
this.beginY = y
for (var i=this.layers.length-1;i>=0;i--) {
if(x>this.layers[i].x && y>this.layers[i].y && x<this.layers[i].w+this.layers[i].x && y<this.layers[i].h+this.layers[i].y){
this.layers[i].isDrag = true
// 获取当前选中的图片对象
let selectObj = this.layers[i]
// 在layers中删除该图片对象
this.layers.splice(i,1)
// 重新将该选中对象添加到layers数组末尾(修改当前图片对象的层级)
this.layers.push(selectObj)
console.log(selectObj)
// 别忘了 break!!
break
}
}
},
上面我们已经将当前被选中的对象移到了layers数组的尾部,因此在长按移动图片这一步骤中,我们就只需判断layers[layers.length - 1] 对象的isDrag属性是否为true,如果是则获取每次移动了的多少距离,并不断修改被选中图片的左上角坐标点。
*注:每次移动都要清空画布,不然会在画布上留下图片被拖动的残影。。be like:
handleTouchMove(e){
if(this.layers.length != 0 && this.layers[this.layers.length-1].isDrag == true){
let {x,y} = e.changedTouches[0]
this.movedX = x-this.beginX
this.movedY = y-this.beginY
this.layers[this.layers.length-1].x += this.movedX
this.layers[this.layers.length-1].y += this.movedY
this.beginX = x
this.beginY = y
}
this.ctx.clearRect(0,0,750,900)
this.layers.forEach(l=>this.darwImages(l.resoure,l.x,l.y,l.w,l.h))
},
结束移动图片只需要重新将isDrag改为false就行了,没啥要注意的了
handleTouchEnd(e){
if(this.layers.length != 0){
this.layers[this.layers.length-1].isDrag = false
}
}
完整代码
<template>
<view>
<view class="btnBox">
<u-button text="添加图片" @click="selectImage"></u-button>
</view>
<canvas
canvas-id="myCanvas"
id="myCanvas"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
></canvas>
</view>
</template>
<script>
export default {
data(){
return{
ctx:'',
beginX:'',
beginY:'',
movedX:'',
movedY:'',
layers:[],
}
},
onLoad() {
this.ctx = uni.createCanvasContext('myCanvas')
},
methods:{
selectImage(){
uni.chooseImage({
success:(res)=> {
let layer = {
type:'photo',
resoure:res.tempFilePaths[0],
x:0,
y:0,
w:200,
h:150,
isDrag:false
}
this.layers.push(layer)
this.darwImages(res.tempFilePaths[0],layer.x,layer.y,layer.w,layer.h)
}
})
},
darwImages(url,x,y,w,h){
this.ctx.drawImage(url,x,y,w,h)
this.ctx.draw(true)
},
handleTouchStart(e){
let {x,y} = e.changedTouches[0]
this.beginX = x
this.beginY = y
for (var i=this.layers.length-1;i>=0;i--) {
if(x>this.layers[i].x && y>this.layers[i].y && x<this.layers[i].w+this.layers[i].x && y<this.layers[i].h+this.layers[i].y){
this.layers[i].isDrag = true
let selectObj = this.layers[i]
this.layers.splice(i,1)
this.layers.push(selectObj)
console.log(selectObj)
break
}
}
},
handleTouchMove(e){
if(this.layers.length != 0 && this.layers[this.layers.length-1].isDrag == true){
let {x,y} = e.changedTouches[0]
this.movedX = x-this.beginX
this.movedY = y-this.beginY
this.layers[this.layers.length-1].x += this.movedX
this.layers[this.layers.length-1].y += this.movedY
this.beginX = x
this.beginY = y
}
this.ctx.clearRect(0,0,750,900)
this.layers.forEach(l=>this.darwImages(l.resoure,l.x,l.y,l.w,l.h))
},
handleTouchEnd(e){
if(this.layers.length != 0){
this.layers[this.layers.length-1].isDrag = false
}
}
}
}
</script>
<style>i
.btnBox{
display: flex;
}
#myCanvas{
width: 750rpx;
height: 900rpx;
}
</style>
(>人<;)文字表达能力有限 && 菜鸟一枚 ,如有问题,欢迎指出~