具体样式
功能:
- 上传文件: 上传文件并保存文件数据
- 预览:将上传的文件转换成图片地址,显示在页面上
- 截图:固定选择框背景,然后将图片数据放置到canvas中进行移动放大然后进行裁切
- 下载:将裁切的数据进行转换,转成可以下载的图片格式,进行下载
视图代码
<template>
<div class="avatar">
<a-button class="btn">
<span>上传头像</span>
<input type="file" name="" id="upload_file" @change="handleChange">
</a-button>
<!-- 预览和剪切的弹框-->
<a-modal v-model="visible" title="图片预览或编辑" @ok="handleOk" class="avatar_modal">
<div class="main">
<img :src="imgSrc" alt="" v-if="isView">
<template v-else>
<div>
<!-- 滑块放大图片-->
<input id="slider" type="range" max="4" min="1" v-model="currentSize" @input="handleRange"/>
</div>
<div id="demo">
<canvas id="myCanvas" width="400px" height="400px" ref="canvas"></canvas>
<canvas id="myImg" width="400px" height="400px" ref="myImg"></canvas>
</div>
</template>
</div>
<div class="model_btn">
<a-button style="margin-right:20px" @click="handleView('VIEW')">预览</a-button>
<a-button @click="handleView('CLIP')">截图</a-button>
</div>
</a-modal>
</div>
</template>
data数据和props数据代码
data(){
return {
visible:false, // 打开预览和截图弹框
isView:true, // 切换预览还是截图
imgSrc:'', // 预览图片地址
currentSize:1, // 图片放大倍数(1-4)
move:{ // canvas中图像的运动的路径数据
lastMoveX:null,
lastMoveY:null,
currentMoveX:null,
currentMoveY:null,
isMoving:false
},
canvas_edit:{ // 被编辑的图片canvas
el:null, //canvas元素
ctx:null, // canvas的2d环境
image:null, // canvas图像元素
left:0, // canvas距离父元素的左侧的宽度
top:0 // canvas距离父元素顶部的高度
},
blackMask:{ // 选择框的canvas元素数据
el:null, // canvas元素
ctx:null // canvas的2d环境
}
}
},
props:{
// 限制的上传格式
limited:{
default:()=>{return ['image/png']},
type:Array
}
},
文件上传和图片预览
handleChange(e){
let file_dom = document.getElementById('upload_file')
let file = e.target.files[0]
if(this.limited.includes(file.type)){
this.imgSrc = window.URL.createObjectURL(file)
this.visible = true
}else{
let str = this.limited.reduce((total,currentValue) =>{ return total + currentValue.split('/')[1] + '、'} ,'')
this.$message.warn('上传文件格式错误,仅支持'+str)
}
file_dom.value = null
}
描述:
- 获取上传的文件
file - 判断
file的 格式,不合格给予提示 - 将
file转换成可以显示的图片地址imgSrc - 将图片显示到对应的节点上实现预览
- 清除上传文件的缓存
初始化mask和canvas图片
drawCanavs(){
this.$nextTick(() =>{
this.canvas_edit.el = this.$refs.canvas // 这个是操作图片的canvas
this.canvas_edit.ctx = this.canvas_edit.el.getContext('2d')
this.canvas_edit.image = new Image()
this.canvas_edit.image.src = this.imgSrc
this.canvas_edit.image.onload = () =>{
this.initCanvas() //初始化canvas元素
}
// 初始化mask的元素
this.blackMask.el = this.$refs.myImg
this.blackMask.ctx = this.blackMask.el.getContext('2d')
this.blackMask.ctx.fillStyle = 'rgba(0,0,0,0.3)'
this.blackMask.ctx.fillRect(0,0,400,400)
this.blackMask.ctx.clearRect(100,100,200,200)
// 由于无法直接在canvas_edit.el元素上监听到数据,可以选择在mask中进行
this.blackMask.el.onmousedown = (e) =>{
this.move.isMoving = true
this.move.lastMoveX = e.clientX
this.move.lastMoveY = e.clientY
}
this.blackMask.el.onmousemove = (e) =>{
if(this.move.isMoving){
let width = e.clientX - this.move.lastMoveX + this.canvas_edit.left
let height = e.clientY - this.move.lastMoveY+this.canvas_edit.top
this.drawCanvas(width,height)
}
}
this.blackMask.el.onmouseup = (e) =>{
if(this.move.isMoving){
this.move.isMoving = false
let width = e.clientX - this.move.lastMoveX + this.canvas_edit.left
let height = e.clientY - this.move.lastMoveY+this.canvas_edit.top
this.drawCanvas(width,height)
this.canvas_edit.left = width
this.canvas_edit.top = height
}
}
})
},
// 绘制居中绘制图片到canvas图像
initCanvas(){
let width = (400 - this.canvas_edit.image.width*this.currentSize)/2 //图片的初始坐标(width,heigth)
let height = (400 - this.canvas_edit.image.height*this.currentSize)/2
this.canvas_edit.left = width
this.canvas_edit.top = height
this.canvas_edit.ctx.drawImage(this.canvas_edit.image,width,height,this.canvas_edit.image.width*this.currentSize,this.canvas_edit.image.height*this.currentSize)
},
// 更新canvas图像
drawMask(width,height){
this.canvas_edit.ctx.clearRect(0,0,400,400)
this.canvas_edit.ctx.drawImage(this.canvas_edit.image,width,height,this.canvas_edit.image.width * this.currentSize,this.currentSize * this.canvas_edit.image.height)
},
描述:
- 绘制图像到canvas图像中
- 绘制遮罩层
- 在制遮罩层中绑定按下、移动、按上的事件
- 在按下的时候,确定好当前的鼠标所在的位置
- 在移动的时候,根据鼠标移动的距离来移动canvas图像中图片移动的位置,对canvas图像进行更新
- 在按上的时候,确定鼠标离开时的位置做为canvas图像中图片的坐标,并更新图像
剪裁和下载
handleOk(){
// 获取裁切到的图像数据
let image_data = this.canvas_edit.ctx.getImageData(100,100,200,200)
this.canvas_edit.ctx.clearRect(0,0,400,400)
// 将canvas修改成和选中图像一样大的宽高
this.canvas_edit.el.height = 200
this.canvas_edit.el.width = 200
this.canvas_edit.el.style.left = '100px'
this.canvas_edit.el.style.top = '100px'
this.canvas_edit.ctx.putImageData(image_data,0,0) // 将裁切到的元素放到canvas中
// 将canvas图像转换成可下的图片格式,并下载
let base64_img = this.canvas_edit.el.toDataURL('image/png')
let blob_img = this.dataURLToBlob(base64_img)
let url = URL.createObjectURL(blob_img)
let a = document.createElement('a')
a.setAttribute('download', '头像数据' + '.png')
a.setAttribute('href',url)
a.click()
this.visible = false
this.$emit('getUrl',url)
}
// base64转换成Blob对象
dataURLToBlob(code) {
let parts = code.split(';base64,')
let contentType = parts[0].split(':')[1]
let raw = window.atob(parts[1])
let rawLength = raw.length
let uInt8Array = new Uint8Array(rawLength)
for(let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i)
}
return new Blob([uInt8Array], {
type: contentType
})
},
描述:
- 获取canvas图像中被选中的图像数据
- 清屏,修改canvas元素的大小,并将canvas图像放置到中心
- 将获取到的图像数据放到canvas元素中
- 将canvas转换成可下载的图像进行下载