用Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能

  • 图片上传
  • 图片压缩
  • 拖拽排序、拖拽删除



之前在公司开发过一段时间的移动端H5页面,有个功能就是要上传图片+压缩。参考了一下网上的方法,外加自己摸索的过程,最终实现了这个功能。后面在家闲的时候又加多了个长按选中图片,并且可以拖拽排序、拖拽到指定位置删除的功能。

github地址:代码地址

下面直接进入正题:

图片上传

图片上传用的是HTML的input标签实现的。核心就是把获取到的文件通过FileReader转换成图片,代码如下:

<input type="file" accept="image/*" capture="camera" @change="selectFile">

selectFile(event:any){
   	this.showAlert = false      
  	if (event.target.files && event.target.files.length > 0) {
         this.isLoading = true
         let file:any = event.target.files[0]
         let fr:any = new FileReader()
         fr.readAsDataURL(file)
         fr.onload = (imgObj:any) => {
             let img:any = new Image()
             img.src = imgObj.target.result
             img.onload = (e:any) => {
                 // 这里就可以获取到上传的图片了
                 })
             }
         }
     }
}

图片压缩

图片压缩用的是canvas重绘的方法实现的,具体代码如下:

// 省略上面的代码
fr.onload = (imgObj:any) => {
	// 获取到图片文件后
   let img:any = new Image()
   img.src = imgObj.target.result
   img.onload = (e:any) => {
       Compress(img,e.path[0].height,e.path[0].width,(newImg:any) => {
           this.imgList.push(newImg)
           this.isLoading = false
           // 待添加拖拽功能
       })
   }
}

/**
 * 图片压缩
 * @param img 图片对象
 */
export function Compress(img:any,height:number,width:number,callback:Function) {
    let canvas:any = document.createElement('canvas')
    let context:any = canvas.getContext('2d')
    canvas.width = width
    canvas.height = height
    context.clearRect(0,0,width,height)
    context.drawImage(img,0,0,width,height)
    callback(canvas.toDataURL("image/jpeg", 0.75))
}

拖拽排序、拖拽删除

拖拽排序、拖拽到指定位置删除是通过监听touch事件来实现的。
核心思路:
1、获取到图片dom元素,给图片dom元素添加ontouchstart、ontouchend、ontouchmove 方法。
2、在ontouchstart方法中new一个时间节点,在ontouchend中也new一个时间节点,通过判断两个时间节点之间的时间间隔判断是点击事件还是长按事件。
3、ontouchstart中设置settimeout方法是延时判断是点击方法还是长按方法,如果是长按方法的则获取图片的所在页面中的位置,设置图片的位置为点击屏幕的位置,改变图片的布局方式,在ontouchmove方法中设置图片的位置跟随触摸屏幕的位置变化。
4、移动图片后松开手时,触发ontouchend方法,判断手指离开后,图片所在的位置是否处在删除的区域当中,如果在则删除图片,并且重新渲染图片列表,重新添加touch方法。
如果不在删除的区域中,则进行图片位置排序,排序后还原图片样式。并强制重新渲染图片列表。

代码如下:

Compress(img,e.path[0].height,e.path[0].width,(newImg:any) => {
  this.imgList.push(newImg)
  this.isLoading = false
  // 在这里给加入方法
   setTimeout(() => {
       this.addTouchEvent()   
   });
})



addTouchEvent(){
    let domList:any = document.querySelectorAll('.show-img')
    if (domList) {
        let domMoveFlag:boolean = true
        domList.forEach((item:any,index:any) => {
            item.ontouchstart = null
            item.ontouchmove = null
            item.ontouchend = null
            item.ontouchstart = (startEvent:any) => {
                startEvent.preventDefault()
                console.log(startEvent)
                this.touchStartTime = new Date()
                setTimeout(() => {  
                    if (domMoveFlag) {     
                        console.log('执行元素位置操作过程')
                        this.showDeleteArea = true
                        let domClient:any = item.getBoundingClientRect()
                        console.log(domClient)
                        this.firstPosition = {
                            x:startEvent.changedTouches[0].pageX,
                            y:startEvent.changedTouches[0].pageY
                        }
                        item.style.position = 'fixed'
                        item.style.height = domClient.height + 'px'
                        item.style.width = domClient.width + 'px'
                        item.style.top = domClient.top + 'px'
                        item.style.left = domClient.left + 'px'
                        item.style.padding = 0
                        item.style.zIndex = 9
                        // 添加拖拽事件
                        item.ontouchmove = (moveEvent:any) => {
                            // console.log(moveEvent)
                            item.style.top = moveEvent.changedTouches[0].pageY - this.firstPosition.y + domClient.top + 'px'
                            item.style.left = moveEvent.changedTouches[0].pageX - this.firstPosition.x + domClient.left + 'px'
                        }                        
                    }          
                }, 600);
            }
            item.ontouchend = (endEvent:any) => {
                let time:any = new Date()
                console.log(time - this.touchStartTime)
                if (time - this.touchStartTime <= 400) {
                    domMoveFlag = false
                    item.click()
                    setTimeout(() => {
                        this.addTouchEvent()   
                    });
                } else {
                    let newItemCenter:any = item.getBoundingClientRect()
                    let centerY:any = newItemCenter.top + newItemCenter.height / 2
                    let centerX:any = newItemCenter.left + newItemCenter.width / 2
                    let deleteDom:any = document.querySelector(".deleteImg")
                    let deleteArea:any = deleteDom.getBoundingClientRect()
                    if (centerY >= deleteArea.top) {
                        let _imgList = JSON.parse(JSON.stringify(this.imgList))
                        let currentImg:any = _imgList.splice(index,1)
                        this.imgList = []
                        this.showDeleteArea = false
                        setTimeout(() => {
                            this.imgList = _imgList
                            setTimeout(() => {
                                this.addTouchEvent()   
                            });
                        });
                        return
                    }
                    this.showDeleteArea = false
                    // 计算所有图片元素所在页面位置
                    let domParentList:any = document.querySelectorAll('.imgCtn')
                    domParentList && domParentList.forEach((domParent:any,cindex:any) => {
                        let domPos:any = (domParent.getBoundingClientRect())
                        if ( 
                            centerY >= domPos.top 
                            && centerY <= domPos.bottom 
                            && centerX >= domPos.left
                            && centerX <= domPos.right
                        ) {
                            // 重新排序
                            console.log('在目标区域内,重新排序')
                            let _imgList = JSON.parse(JSON.stringify(this.imgList))
                            let currentImg:any = _imgList.splice(index,1)
                            _imgList.splice(cindex,0,...currentImg)
                            this.imgList = []
                            setTimeout(() => {
                                this.imgList = _imgList
                                setTimeout(() => {
                                    this.addTouchEvent()   
                                });
                            });
                        }
                    });
                    // 还原样式
                    item.style.position = 'absolute';
                    item.style.height = '100%'
                    item.style.width = '100%'
                    item.style.top = '0'
                    item.style.left = '0'
                    item.style.padding = '10px'
                }
            }
        })
    }
}

至此,图片的上传、压缩、拖拽排序、拖拽删除功能就已经完成了。