当前位置: 首页 > 工具软件 > Tailor > 使用案例 >

vue头像加白边_vue,vue-avatar-tailor,vue头像裁剪组件 - SegmentFault 思否

卫念
2023-12-01

上传图片

通过临时生成的img标签获取图片的大小信息(getImgSize函数的具体实现请参考源码)

比较原图长和宽,以其长边作为标准进行图片的缩放显示,让整张图显示在待裁剪区域中

以图片缩放后的短边作为选择框的宽,使裁剪框初始显示为最大可选范围

从而解决【裁剪框初始宽高】问题

// 选择图片

fileChange(event) {

const fileObj = event.target.files[0]

const reader = new FileReader()

reader.onload = () => {

const { selectData, containerBoxData } = this

this.imgURL = reader.result

this.getImgSize(this.imgURL).then((result) => { // 获取图片的大小

if (result.width > result.height) { // 350为外盒子宽高,比较原图长和宽,以其长边作为标准进行图片的缩放显示

this.scaleRate = 350 / result.width // 获取并记录图片缩放比

containerBoxData.width = 350

containerBoxData.height = Math.floor(result.height * this.scaleRate)

selectData.top = 0

selectData.left = (350 - containerBoxData.height) / 2 // 裁剪选择框居中显示

selectData.width = containerBoxData.height // 以图片缩放后的短边作为选择框的宽,使其显示为最大可选范围

} else {

this.scaleRate = 350 / result.height

containerBoxData.height = 350

containerBoxData.width = Math.floor(result.width * this.scaleRate)

selectData.left = 0

selectData.top = (350 - containerBoxData.width) / 2

selectData.width = containerBoxData.width

}

this.setPreview()

})

}

reader.readAsDataURL(fileObj)

},

遮罩镂空的效果实现思路如下

共通过三个元素重叠显示,原图img标签放在最底下,遮罩层.img-mask放在中间,裁剪区域.select-box放在最外层

.img-mask是遮住了整个img标签的,只是裁剪区域.select-box显示的内容刚好与原图上的一致。实现看起来遮罩被镂空的效果

其实遮罩并没有被镂空,只是遮罩上又多了一层图案,刚刚与原位置相同

裁剪区域.select-box,显示的内容和位置,通过background相关属性,background-position 和 background-size在实现

即选取图片的特定区域作为裁剪区域.select-box的背景

@mousedown="onMouseDown($event, 'move')" :style="{

top:`${selectData.top}px`,

left:`${selectData.left}px`,

width:`${selectData.width}px`,

height:`${selectData.width}px`,

'background-image':`url(${imgURL})`,

'background-position':`${-selectData.left}px ${-selectData.top}px`,

'background-size':`${containerBoxData.width}px ${containerBoxData.height}px`,

}">

渲染预览效果

利用canvas的drawImage函数,将候选区域显示在预览区

drawImage函数可以设置图形采取的范围和位置

并设置采取获得的图形,显示在canvas的那个地方,以多大的size显示

从而实现采取区,于预览区缩放的形式显示

实现【实时预览】效果

// 设置预览图

setPreview() {

const { selectData, scaleRate } = this

const $canvas = this.$refs.$canvas.getContext('2d')

$canvas.clearRect(0, 0, 190, 190) // 清除canvas中的内容

$canvas.drawImage( // 将原图中,选定区域的图案通过canvas渲染出来

this.$refs.$img, // 图形元素

Math.floor(selectData.left / scaleRate), // 截取原图中的那个位置作为起始点,X轴方向上

Math.floor(selectData.top / scaleRate), // 截取原图中的那个位置作为起始点,Y轴方向上

selectData.width / scaleRate, // 截取原图中多大的范围,宽度

selectData.width / scaleRate, // 截取原图中多大的范围,高度

0, // 显示在canvas中的X坐标

0, // 显示在canvas中的Y坐标

190, // 将内容伸缩为多大的宽度显示

190, // 将内容伸缩为多大的高度显示

)

},

拉伸操作的监听

在裁剪区域中,使用ul,li标签充当各个操作点,及形成九宫格中的虚线功能

在每个操作点中,监听mousedown事件,记录即将移动的方向,表示接下来的mousemove事件中,是进行那个方向上的拉伸

在created钩子中,监听全局 mouseup 和 mousemove 事件。因为鼠标的离开和利用不一样在裁剪区域中,在其他地方触发也应该同样执行相关操作

在 mousemove 事件中区裁剪区移动操作「move」,裁剪区拉伸操作「stretch」。执行不同的函数

数据设置完成后,重新渲染预览区

实现【拖拽范围扩展位置计算】及【拖拽范围扩展约束】功能

onMouseMove(event) {

const { selectData, containerBoxData } = this

const { x, y } = selectData.originPoint

const moveX = event.clientX - x // X轴移动的距离

const moveY = event.clientY - y // Y轴移动的距离

if (selectData.action === 'move') { // 移动选择框

this.doMove(selectData, containerBoxData, moveX, moveY)

} else if (selectData.action === 'stretch') { // 拉伸选择框

this.doStretch(selectData, containerBoxData, moveX, moveY)

} else {

return

}

selectData.originPoint = {

x: event.clientX > 0 ? event.clientX : 0,

y: event.clientY > 0 ? event.clientY : 0,

}

this.setPreview()

},

裁剪区移动

比较移动后上下左右各个边与原图可裁剪区域的位置关系

若超出范围,则设置为边界值

实现【移动范围约束】功能

// 鼠标移动

doMove(selectData, containerBoxData, moveX, moveY) {

selectData.top += moveY

selectData.left += moveX

if (selectData.top < 0) {

selectData.top = 0

}

if (selectData.left < 0) {

selectData.left = 0

}

if (selectData.top + selectData.width > containerBoxData.height) {

selectData.top = containerBoxData.height - selectData.width

}

if (selectData.left + selectData.width > containerBoxData.width) {

selectData.left = containerBoxData.width - selectData.width

}

},

裁剪区拉伸

设置各个方位具体的拉伸操作

调用对应函数,先进行一次拉伸操作

拉伸完成后,比较上下左右,宽高的溢出情况,获得最大的溢出值

以最大溢出值进行反向操作,确保裁剪区一直在可选范围内

// 选择框拉伸

doStretch(selectData, containerBoxData, moveX, moveY) {

const { minWidth } = this

// 比较上下左右,宽高的溢出情况,返回最大的溢出值

function getOverflowLength() {

const overflowLeft = selectData.left < 0 ? -selectData.left : 0

const overflowTop = selectData.top < 0 ? -selectData.top : 0

const overflowRight = selectData.left + selectData.width > containerBoxData.width ? selectData.left + selectData.width - containerBoxData.width : 0

const overflowBottom = selectData.top + selectData.width > containerBoxData.height ? selectData.top + selectData.width - containerBoxData.height : 0

const overflowWidth = selectData.width < minWidth ? minWidth - selectData.width : 0

return Math.max(overflowLeft, overflowTop, overflowRight, overflowBottom, overflowWidth)

}

// 向左拉伸

function doStretchLeft(action) {

let space = moveX

space = action === 'preDo' ? space : -space

selectData.top += space / 2

selectData.left += space

selectData.width -= space

}

function doStretchRight(action) {

let space = moveX

space = action === 'preDo' ? space : -space

selectData.top -= space / 2

selectData.width += space

}

function doStretchTop(action) {

let space = moveY

space = action === 'preDo' ? space : -space

selectData.top += space

selectData.left += space / 2

selectData.width -= space

}

function doStretchBottom(action) {

let space = moveY

space = action === 'preDo' ? space : -space

selectData.left -= space / 2

selectData.width += space

}

function doStretchTopLeft(action) {

let space = Math.abs(moveX) > Math.abs(moveY) ? moveX : moveY

space = action === 'preDo' ? space : -space

selectData.top += space

selectData.left += space

selectData.width -= space

}

function doStretchTopRight(action) {

let space = Math.abs(moveX) > Math.abs(moveY) ? moveX : -moveY

space = action === 'preDo' ? space : -space

selectData.top -= space

selectData.width += space

}

function doStretchBottomLeft(action) {

let space = Math.abs(moveX) > Math.abs(moveY) ? moveX : -moveY

space = action === 'preDo' ? space : -space

selectData.left += space

selectData.width -= space

}

function doStretchBottomRight(action) {

let space = Math.abs(moveX) > Math.abs(moveY) ? moveX : moveY

space = action === 'preDo' ? space : -space

selectData.width += space

}

const doStretchFun = {

doStretchLeft,

doStretchRight,

doStretchTop,

doStretchBottom,

doStretchTopLeft,

doStretchTopRight,

doStretchBottomLeft,

doStretchBottomRight,

}[`doStretch${this.getWord(this.getCamelCase(selectData.direction))}`]

// 进行拉伸操作

doStretchFun('preDo')

let overflowLength = getOverflowLength() // 拉伸完成后,获取最大溢出值

if (overflowLength > 0) { // 以最大溢出值进行反向操作,确保裁剪区一直在可选范围内

doStretchFun('reset')

}

},

 类似资料: