1293 lines
42 KiB
Plaintext
1293 lines
42 KiB
Plaintext
<template>
|
||
<view class="image-cropper" catchtouchmove="_preventTouchMove">
|
||
<view class="main" id="main_bc" @touchend="_cutTouchEnd" @touchstart="_cutTouchStart" @touchmove="_cutTouchMove">
|
||
<view class="content">
|
||
<view class="content_top bg_gray {{_flag_bright? '':'bg_black'}}"
|
||
style="height:{{cut_top}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
|
||
<view class="content_middle" style="height:{{height}}px;">
|
||
<view class="content_middle_left bg_gray {{_flag_bright? '':'bg_black'}}"
|
||
style="width:{{cut_left}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
|
||
<view class="content_middle_middle"
|
||
style="width:{{width}}px;height:{{height}}px;transition-duration: .3s;transition-property:{{_cut_animation?'':'background'}};">
|
||
<view class="border border-top-left" style="background: {{borderColor}}"></view>
|
||
<view class="border border-top-right" style="background: {{borderColor}}"></view>
|
||
<view class="border border-right-top" style="background: {{borderColor}}"></view>
|
||
<view class="border border-right-bottom" style="background: {{borderColor}}"></view>
|
||
<view class="border border-bottom-right" style="background: {{borderColor}}"></view>
|
||
<view class="border border-bottom-left" style="background: {{borderColor}}"></view>
|
||
<view class="border border-left-bottom" style="background: {{borderColor}}"></view>
|
||
<view class="border border-left-top" style="background: {{borderColor}}"></view>
|
||
</view>
|
||
<view class="content_middle_right bg_gray {{_flag_bright? '':'bg_black'}}"
|
||
style="transition-property:{{_cut_animation?'':'background'}}"></view>
|
||
</view>
|
||
<view class="content_bottom bg_gray {{_flag_bright?'':'bg_black'}}"
|
||
style="transition-property:{{_cut_animation?'':'background'}}"></view>
|
||
</view>
|
||
<image @load="imageLoad" bindtouchstart="_start" bindtouchmove="_move" bindtouchend="_end"
|
||
style="width:{{img_width ? img_width + 'px' : 'auto'}};height:{{img_height ? img_height + 'px' : 'auto'}};top:{{tanTop}};left:{{tanLeft}};transform:translate3d({{tanTop=='50%'?'-'+tanTop:_img_left-img_width/2+'px'}},{{tanLeft=='50%'?'-'+tanLeft:_img_top-img_height/2+'px'}},0) scale({{scale}}) rotate({{angle}}deg);transition-duration:{{_cut_animation?.4:0}}s;"
|
||
class="img"
|
||
:src="imgSrc"></image>
|
||
</view>
|
||
<canvas canvas-id="image-cropper" disable-scroll="true"
|
||
style="width:{{_canvas_width * export_scale}}px;height:{{_canvas_height * export_scale}}px;left:{{canvas_left}}px;top:{{canvas_top}}px"
|
||
class="image-cropper-canvas"></canvas>
|
||
</view>
|
||
<view class="main-box">
|
||
<view class="main-cancel ~flo_l ~font_30 ~text-center" @tap.stop="chooseimage">选择图片</view>
|
||
<view class="main-save ~flo_r ~font_30 ~text-center" @tap.stop="saveUpdate">确定</view>
|
||
</view>
|
||
<chooseImageTips :chooseShow.sync="chooseShow" @hideCut.user="hideCut" @imgSrcCut.user="imgSrcCut"></chooseImageTips>
|
||
</template>
|
||
<script>
|
||
import wepy from '@wepy/core'
|
||
wepy.component({
|
||
// config = {
|
||
// component: true
|
||
// }
|
||
// components = {chooseImageTips}
|
||
props: {
|
||
/**
|
||
* 图片路径
|
||
*/
|
||
imgSrc: {
|
||
type: String
|
||
},
|
||
/**
|
||
* 裁剪框颜色
|
||
*/
|
||
borderColor: {
|
||
type: String,
|
||
default: 'white'
|
||
},
|
||
/**
|
||
* 裁剪框高度
|
||
*/
|
||
height: {
|
||
type: Number,
|
||
default: 200
|
||
},
|
||
/**
|
||
* 裁剪框宽度
|
||
*/
|
||
width: {
|
||
type: Number,
|
||
default: 200
|
||
},
|
||
/**
|
||
* 裁剪框最小尺寸
|
||
*/
|
||
min_width: {
|
||
type: Number,
|
||
default: 100
|
||
},
|
||
min_height: {
|
||
type: Number,
|
||
default: 100
|
||
},
|
||
/**
|
||
* 裁剪框最大尺寸
|
||
*/
|
||
max_width: {
|
||
type: Number,
|
||
default: 300
|
||
},
|
||
'max_height': {
|
||
type: Number,
|
||
default: 300
|
||
},
|
||
/**
|
||
* 裁剪框禁止拖动
|
||
*/
|
||
disable_width: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
disable_height: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
/**
|
||
* 锁定裁剪框比例
|
||
*/
|
||
disable_ratio: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
/**
|
||
* 生成的图片尺寸相对剪裁框的比例
|
||
*/
|
||
export_scale: {
|
||
type: Number,
|
||
default: 1
|
||
},
|
||
/**
|
||
* 生成的图片质量0-1
|
||
*/
|
||
quality: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
cut_top: {
|
||
type: Number,
|
||
default: 212
|
||
},
|
||
cut_left: {
|
||
type: Number,
|
||
default: 37
|
||
},
|
||
/**
|
||
* canvas上边距(不设置默认不显示)
|
||
*/
|
||
canvas_top: {
|
||
type: Number,
|
||
default: null
|
||
},
|
||
/**
|
||
* canvas左边距(不设置默认不显示)
|
||
*/
|
||
canvas_left: {
|
||
type: Number,
|
||
default: null
|
||
},
|
||
/**
|
||
* 图片宽度
|
||
*/
|
||
img_width: {
|
||
type: Number,
|
||
default: null
|
||
},
|
||
/**
|
||
* 图片高度
|
||
*/
|
||
img_height: {
|
||
type: Number,
|
||
default: null
|
||
},
|
||
/**
|
||
* 图片缩放比
|
||
*/
|
||
scale: {
|
||
type: Number,
|
||
default: 1
|
||
},
|
||
/**
|
||
* 图片旋转角度
|
||
*/
|
||
angle: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
/**
|
||
* 判断是否是新图片
|
||
*/
|
||
newPic: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
/**
|
||
* 最小缩放比
|
||
*/
|
||
min_scale: {
|
||
type: Number,
|
||
default: 0.5
|
||
},
|
||
/**
|
||
* 最大缩放比
|
||
*/
|
||
max_scale: {
|
||
type: Number,
|
||
default: 2
|
||
},
|
||
/**
|
||
* 是否禁用旋转
|
||
*/
|
||
disable_rotate: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
/**
|
||
* 是否限制移动范围(剪裁框只能在图片内)
|
||
*/
|
||
limit_move: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
},
|
||
data: {
|
||
el: 'image-cropper', // 暂时无用
|
||
info: wx.getSystemInfoSync(),
|
||
MOVE_THROTTLE: null, // 触摸移动节流settimeout
|
||
MOVE_THROTTLE_FLAG: true, // 节流标识
|
||
INIT_IMGWIDTH: 0, // 图片设置尺寸,此值不变(记录最初设定的尺寸)
|
||
INIT_IMGHEIGHT: 0, // 图片设置尺寸,此值不变(记录最初设定的尺寸)
|
||
TIME_BG: null, // 背景变暗延时函数
|
||
TIME_CUT_CENTER: null,
|
||
_touch_img_relative: [{
|
||
x: 0,
|
||
y: 0
|
||
}], // 鼠标和图片中心的相对位置
|
||
_flag_cut_touch: false, // 是否是拖动裁剪框
|
||
_hypotenuse_length: 0, // 双指触摸时斜边长度
|
||
_flag_img_endtouch: false, // 是否结束触摸
|
||
_flag_bright: true, // 背景是否亮
|
||
_canvas_overflow: true, // canvas缩略图是否在屏幕外面
|
||
_canvas_width: 200,
|
||
_canvas_height: 200,
|
||
origin_x: 0.5, // 图片旋转中心
|
||
origin_y: 0.5, // 图片旋转中心
|
||
_cut_animation: false, // 是否开启图片和裁剪框过渡
|
||
_img_top: wx.getSystemInfoSync().windowHeight / 2, // 图片上边距
|
||
_img_left: wx.getSystemInfoSync().windowWidth / 2, // 图片左边距
|
||
chooseShow: false,
|
||
tanTop: '50%',
|
||
tanLeft: '50%'
|
||
|
||
},
|
||
watch: {
|
||
// 监听截取框宽高变化
|
||
width(newV, oldV) {
|
||
if (newV < this.min_width) {
|
||
this.width = this.min_width
|
||
}
|
||
this._computeCutSize()
|
||
},
|
||
height(newV, oldV) {
|
||
if (newV < this.min_height) {
|
||
this.height = this.min_height
|
||
}
|
||
this._computeCutSize()
|
||
},
|
||
angle(newV, oldV) {
|
||
// 停止居中裁剪框,继续修改图片位置
|
||
this._moveStop()
|
||
if (this.limit_move) {
|
||
if (this.angle % 90) {
|
||
this.angle = Math.round(this.angle / 90) * 90
|
||
}
|
||
}
|
||
},
|
||
_cut_animation(newV, oldV) {
|
||
// 开启过渡300毫秒之后自动关闭
|
||
clearTimeout(this._cut_animation_time)
|
||
if (newV) {
|
||
this._cut_animation_time = setTimeout(() => {
|
||
this._cut_animation = false
|
||
}, 300)
|
||
}
|
||
},
|
||
limit_move(newV) {
|
||
if (newV) {
|
||
if (this.angle % 90) {
|
||
this.angle = Math.round(this.angle / 90) * 90
|
||
}
|
||
this._imgMarginDetectionScale()
|
||
!this._canvas_overflow && this._draw()
|
||
}
|
||
},
|
||
canvas_top() {
|
||
this._canvasDetectionPosition()
|
||
},
|
||
canvas_left() {
|
||
this._canvasDetectionPosition()
|
||
},
|
||
imgSrc(e) {
|
||
this.pushImg()
|
||
},
|
||
cut_top() {
|
||
this._cutDetectionPosition()
|
||
if (this.limit_move) {
|
||
!this._canvas_overflow && this._draw()
|
||
}
|
||
},
|
||
cut_left() {
|
||
this._cutDetectionPosition()
|
||
if (this.limit_move) {
|
||
!this._canvas_overflow && this._draw()
|
||
}
|
||
}
|
||
},
|
||
ready() {
|
||
this.info = wx.getSystemInfoSync()
|
||
this.INIT_IMGWIDTH = this.img_width
|
||
this.INIT_IMGHEIGHT = this.img_height
|
||
this._canvas_height = this.height
|
||
this._canvas_width = this.width
|
||
console.log('--9988')
|
||
this._initCanvas()
|
||
this.imgSrc && (this.imgSrc = this.imgSrc)
|
||
// 根据开发者设置的图片目标尺寸计算实际尺寸
|
||
this._initImageSize()
|
||
// 设置裁剪框大小>设置图片尺寸>绘制canvas
|
||
this._computeCutSize()
|
||
// 检查裁剪框是否在范围内
|
||
this._cutDetectionPosition()
|
||
// 检查canvas是否在范围内
|
||
this._canvasDetectionPosition()
|
||
this.setCutCenter()
|
||
this.$emit('load', {
|
||
cropper: this
|
||
})
|
||
},
|
||
// 渲染
|
||
methods: {
|
||
_draw(callback) {
|
||
console.log(this.imgSrc)
|
||
if (!this.imgSrc || !this.ctx) return
|
||
let draw = () => {
|
||
// 图片实际大小
|
||
let img_width = this.img_width * this.scale * this.export_scale
|
||
let img_height = this.img_height * this.scale * this.export_scale
|
||
// canvas和图片的相对距离
|
||
var xpos = this._img_left - this.cut_left
|
||
var ypos = this._img_top - this.cut_top
|
||
// 旋转画布
|
||
this.ctx.translate(xpos * this.export_scale, ypos * this.export_scale)
|
||
this.ctx.rotate(this.angle * Math.PI / 180)
|
||
this.ctx.drawImage(this.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height)
|
||
this.ctx.draw(false, () => {
|
||
callback && callback()
|
||
})
|
||
}
|
||
console.log(this.ctx, 'this.ctx=333')
|
||
if (this.ctx && (this.ctx.width != this.width || this.ctx.height != this.height)) {
|
||
// 优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方
|
||
this._canvas_height = this.height
|
||
this._canvas_width = this.width
|
||
draw()
|
||
this._canvas_height = this.height
|
||
this._canvas_width = this.width
|
||
} else {
|
||
draw()
|
||
}
|
||
},
|
||
|
||
chooseimage() {
|
||
let vm = this
|
||
vm.chooseShow = true
|
||
vm.newPic = 1
|
||
// wx.chooseImage({
|
||
// count: 1,
|
||
// // sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||
// sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||
// sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
|
||
// success: (res) => {
|
||
// vm.imgSrc = res.tempFilePaths[0]
|
||
// console.log(vm.imgSrc)
|
||
// }
|
||
// })
|
||
},
|
||
async saveUpdate(event) {
|
||
// 生成图片并回调
|
||
await this._initCanvas()
|
||
let vm = this
|
||
console.log(this.imgSrc, '//')
|
||
if (!this.imgSrc) return
|
||
if (vm.newPic == 0) {
|
||
console.log('222')
|
||
vm.$emit('saveCut', {
|
||
url: this.imgSrc
|
||
})
|
||
return
|
||
}
|
||
let draw = () => {
|
||
// 图片实际大小
|
||
let img_width = this.img_width * this.scale * this.export_scale
|
||
let img_height = this.img_height * this.scale * this.export_scale
|
||
// canvas和图片的相对距离
|
||
var xpos = this._img_left - this.cut_left
|
||
var ypos = this._img_top - this.cut_top
|
||
// 旋转画布
|
||
vm.ctx.translate(xpos * vm.export_scale, ypos * vm.export_scale)
|
||
vm.ctx.rotate(this.angle * Math.PI / 180)
|
||
vm.ctx.drawImage(vm.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height)
|
||
console.log(vm.ctx, '333')
|
||
vm.ctx.draw(false, () => {
|
||
console.log('444')
|
||
wx.canvasToTempFilePath({
|
||
width: vm.width * vm.export_scale,
|
||
height: Math.round(vm.height * vm.export_scale),
|
||
destWidth: vm.width * vm.export_scale,
|
||
destHeight: Math.round(vm.height) * vm.export_scale,
|
||
fileType: 'png',
|
||
quality: vm.quality,
|
||
canvasId: vm.el,
|
||
success: (res) => {
|
||
console.log(res.tempFilePath, '///')
|
||
vm.$emit('saveCut', {
|
||
url: res.tempFilePath,
|
||
width: vm.width * vm.export_scale,
|
||
height: vm.height * vm.export_scale
|
||
})
|
||
}
|
||
}, vm.$wx)
|
||
})
|
||
}
|
||
if (vm.ctx.width != vm.width || vm.ctx.height != vm.height) {
|
||
// 优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方
|
||
vm._canvas_height = vm.height
|
||
vm._canvas_width = vm.width
|
||
draw()
|
||
vm._canvas_height = vm.height
|
||
vm._canvas_width = vm.width
|
||
} else {
|
||
draw()
|
||
}
|
||
},
|
||
_preventTouchMove(event) {
|
||
},
|
||
// 裁剪框处理
|
||
_cutTouchMove(e) {
|
||
if (this._flag_cut_touch && this.MOVE_THROTTLE_FLAG) {
|
||
// if (this.disable_ratio && (this.disable_width || this.disable_height)) return
|
||
// 节流
|
||
this.MOVE_THROTTLE_FLAG = false
|
||
this._move_throttle()
|
||
let width = this.width,
|
||
height = this.height,
|
||
cut_top = this.cut_top,
|
||
cut_left = this.cut_left,
|
||
size_correct = () => {
|
||
width = width <= this.max_width ? width >= this.min_width ? width : this.min_width : this.max_width
|
||
height = height <= this.max_height ? height >= this.min_height ? height : this.min_height : this.max_height
|
||
},
|
||
size_inspect = () => {
|
||
if ((width > this.max_width || width < this.min_width || height > this.max_height || height < this.min_height) && this.disable_ratio) {
|
||
size_correct()
|
||
return false
|
||
} else {
|
||
size_correct()
|
||
return true
|
||
}
|
||
}
|
||
height = this.CUT_START.height + ((this.CUT_START.corner > 1 && this.CUT_START.corner < 4 ? 1 : -1) * (this.CUT_START.y - e.touches[0].clientY))
|
||
switch (this.CUT_START.corner) {
|
||
case 1:
|
||
width = this.CUT_START.width + this.CUT_START.x - e.touches[0].clientX
|
||
if (this.disable_ratio) {
|
||
height = width / (this.width / this.height)
|
||
}
|
||
if (!size_inspect()) return
|
||
cut_left = this.CUT_START.cut_left - (width - this.CUT_START.width)
|
||
break
|
||
case 2:
|
||
width = this.CUT_START.width + this.CUT_START.x - e.touches[0].clientX
|
||
if (this.disable_ratio) {
|
||
height = width / (this.width / this.height)
|
||
}
|
||
if (!size_inspect()) return
|
||
cut_top = this.CUT_START.cut_top - (height - this.CUT_START.height)
|
||
cut_left = this.CUT_START.cut_left - (width - this.CUT_START.width)
|
||
break
|
||
case 3:
|
||
width = this.CUT_START.width - this.CUT_START.x + e.touches[0].clientX
|
||
if (this.disable_ratio) {
|
||
height = width / (this.width / this.height)
|
||
}
|
||
if (!size_inspect()) return
|
||
cut_top = this.CUT_START.cut_top - (height - this.CUT_START.height)
|
||
break
|
||
case 4:
|
||
width = this.CUT_START.width - this.CUT_START.x + e.touches[0].clientX
|
||
if (this.disable_ratio) {
|
||
height = width / (this.width / this.height)
|
||
}
|
||
if (!size_inspect()) return
|
||
break
|
||
}
|
||
if (!this.disable_width && !this.disable_height) {
|
||
this.width = width
|
||
this.cut_left = cut_left
|
||
this.height = height
|
||
this.cut_top = cut_top
|
||
} else if (!this.disable_width) {
|
||
this.width = width
|
||
this.cut_left = cut_left
|
||
} else if (!this.disable_height) {
|
||
this.height = height
|
||
this.cut_top = cut_top
|
||
}
|
||
this._imgMarginDetectionScale()
|
||
}
|
||
},
|
||
_cutTouchStart(e) {
|
||
let currentX = e.touches[0].clientX
|
||
let currentY = e.touches[0].clientY
|
||
let cutbox_top4 = this.cut_top + this.height - 30
|
||
let cutbox_bottom4 = this.cut_top + this.height + 20
|
||
let cutbox_left4 = this.cut_left + this.width - 30
|
||
let cutbox_right4 = this.cut_left + this.width + 30
|
||
|
||
let cutbox_top3 = this.cut_top - 30
|
||
let cutbox_bottom3 = this.cut_top + 30
|
||
let cutbox_left3 = this.cut_left + this.width - 30
|
||
let cutbox_right3 = this.cut_left + this.width + 30
|
||
|
||
let cutbox_top2 = this.cut_top - 30
|
||
let cutbox_bottom2 = this.cut_top + 30
|
||
let cutbox_left2 = this.cut_left - 30
|
||
let cutbox_right2 = this.cut_left + 30
|
||
|
||
let cutbox_top1 = this.cut_top + this.height - 30
|
||
let cutbox_bottom1 = this.cut_top + this.height + 30
|
||
let cutbox_left1 = this.cut_left - 30
|
||
let cutbox_right1 = this.cut_left + 30
|
||
if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {
|
||
this._moveDuring()
|
||
this._flag_cut_touch = true
|
||
this._flag_img_endtouch = true
|
||
this.CUT_START = {
|
||
width: this.width,
|
||
height: this.height,
|
||
x: currentX,
|
||
y: currentY,
|
||
corner: 4
|
||
}
|
||
} else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {
|
||
this._moveDuring()
|
||
this._flag_cut_touch = true
|
||
this._flag_img_endtouch = true
|
||
this.CUT_START = {
|
||
width: this.width,
|
||
height: this.height,
|
||
x: currentX,
|
||
y: currentY,
|
||
cut_top: this.cut_top,
|
||
cut_left: this.cut_left,
|
||
corner: 3
|
||
}
|
||
} else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {
|
||
this._moveDuring()
|
||
this._flag_cut_touch = true
|
||
this._flag_img_endtouch = true
|
||
this.CUT_START = {
|
||
width: this.width,
|
||
height: this.height,
|
||
cut_top: this.cut_top,
|
||
cut_left: this.cut_left,
|
||
x: currentX,
|
||
y: currentY,
|
||
corner: 2
|
||
}
|
||
} else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {
|
||
this._moveDuring()
|
||
this._flag_cut_touch = true
|
||
this._flag_img_endtouch = true
|
||
this.CUT_START = {
|
||
width: this.width,
|
||
height: this.height,
|
||
cut_top: this.cut_top,
|
||
cut_left: this.cut_left,
|
||
x: currentX,
|
||
y: currentY,
|
||
corner: 1
|
||
}
|
||
}
|
||
},
|
||
_cutTouchEnd(e) {
|
||
this._moveStop()
|
||
this._flag_cut_touch = false
|
||
// console.log(e,'_cutTouchEnd;;;')
|
||
},
|
||
// 点击中间剪裁框处理
|
||
_click(event) {
|
||
console.log(event)
|
||
if (!this.imgSrc) {
|
||
// 调起上传
|
||
this.chooseimage()
|
||
return
|
||
}
|
||
this._draw(() => {
|
||
let x = event.detail ? event.detail.x : event.touches[0].clientX
|
||
let y = event.detail ? event.detail.y : event.touches[0].clientY
|
||
if ((x >= this.cut_left && x <= (this.cut_left + this.width)) && (y >= this.cut_top && y <= (this.cut_top + this.height))) {
|
||
// 生成图片并回调
|
||
wx.canvasToTempFilePath({
|
||
width: this.width * this.export_scale,
|
||
height: Math.round(this.height * this.export_scale),
|
||
destWidth: this.width * this.export_scale,
|
||
destHeight: Math.round(this.height) * this.export_scale,
|
||
fileType: 'png',
|
||
quality: this.quality,
|
||
canvasId: this.el,
|
||
success: (res) => {
|
||
this.$emit('tapcut', {
|
||
url: res.tempFilePath,
|
||
width: this.width * this.export_scale,
|
||
height: this.height * this.export_scale
|
||
})
|
||
}
|
||
}, this.$wx)
|
||
}
|
||
})
|
||
},
|
||
|
||
imageLoad(e) {
|
||
this.$emit('imageload', this.imageObject)
|
||
wx.hideLoading() // 重置图片角度、缩放、位置
|
||
this.imgReset()
|
||
setTimeout(() => {
|
||
}, 100)
|
||
},
|
||
// 开始触摸
|
||
_start(event) {
|
||
this._flag_img_endtouch = false
|
||
if (event.touches.length == 1) {
|
||
// 单指拖动
|
||
this._touch_img_relative[0] = {
|
||
x: (event.touches[0].clientX - this._img_left),
|
||
y: (event.touches[0].clientY - this._img_top)
|
||
}
|
||
} else {
|
||
// 双指放大
|
||
let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX)
|
||
let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY)
|
||
this._touch_img_relative = [{
|
||
x: (event.touches[0].clientX - this._img_left),
|
||
y: (event.touches[0].clientY - this._img_top)
|
||
}, {
|
||
x: (event.touches[1].clientX - this._img_left),
|
||
y: (event.touches[1].clientY - this._img_top)
|
||
}]
|
||
this._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
|
||
}
|
||
!this._canvas_overflow && this._draw()
|
||
},
|
||
_move(event) {
|
||
// console.log('asssssss',event)
|
||
if (this._flag_img_endtouch || !this.MOVE_THROTTLE_FLAG) return
|
||
this.MOVE_THROTTLE_FLAG = false
|
||
this._move_throttle()
|
||
this._moveDuring()
|
||
if (event.touches.length == 1) {
|
||
// 单指拖动
|
||
let left = (event.touches[0].clientX - this._touch_img_relative[0].x),
|
||
top = (event.touches[0].clientY - this._touch_img_relative[0].y)
|
||
// 图像边缘检测,防止截取到空白
|
||
this._img_left = left
|
||
this._img_top = top
|
||
this._imgMarginDetectionPosition()
|
||
this._img_left = this._img_left
|
||
this._img_top = this._img_top
|
||
} else {
|
||
// 双指放大
|
||
let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)),
|
||
height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)),
|
||
hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
|
||
scale = this.scale * (hypotenuse / this._hypotenuse_length),
|
||
current_deg = 0
|
||
scale = scale <= this.min_scale ? this.min_scale : scale
|
||
scale = scale >= this.max_scale ? this.max_scale : scale
|
||
// 图像边缘检测,防止截取到空白
|
||
this.scale = scale
|
||
this._imgMarginDetectionScale()
|
||
// 双指旋转(如果没禁用旋转)
|
||
let _touch_img_relative = [{
|
||
x: (event.touches[0].clientX - this._img_left),
|
||
y: (event.touches[0].clientY - this._img_top)
|
||
}, {
|
||
x: (event.touches[1].clientX - this._img_left),
|
||
y: (event.touches[1].clientY - this._img_top)
|
||
}]
|
||
if (!this.disable_rotate) {
|
||
let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x)
|
||
let first_atan_old = 180 / Math.PI * Math.atan2(this._touch_img_relative[0].y, this._touch_img_relative[0].x)
|
||
let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x)
|
||
let second_atan_old = 180 / Math.PI * Math.atan2(this._touch_img_relative[1].y, this._touch_img_relative[1].x)
|
||
// 当前旋转的角度
|
||
let first_deg = first_atan - first_atan_old,
|
||
second_deg = second_atan - second_atan_old
|
||
if (first_deg != 0) {
|
||
current_deg = first_deg
|
||
} else if (second_deg != 0) {
|
||
current_deg = second_deg
|
||
}
|
||
}
|
||
this._touch_img_relative = _touch_img_relative
|
||
this._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
|
||
|
||
this.angle = this.angle + current_deg
|
||
this.scale = this.scale
|
||
}
|
||
!this._canvas_overflow && this._draw()
|
||
},
|
||
// 结束操作
|
||
_end(event) {
|
||
this._flag_img_endtouch = true
|
||
this._moveStop()
|
||
// console.log(event)
|
||
},
|
||
hideCut(e) {
|
||
this.chooseShow = e.chooseShow
|
||
},
|
||
imgSrcCut(e) {
|
||
this.imgSrc = e.imgSrc
|
||
},
|
||
/**
|
||
* 上传图片
|
||
*/
|
||
upload() {
|
||
let that = this
|
||
wx.chooseImage({
|
||
count: 1,
|
||
sizeType: ['original', 'compressed'],
|
||
sourceType: ['album', 'camera'],
|
||
success(res) {
|
||
const tempFilePaths = res.tempFilePaths[0]
|
||
console.log('Img Temp Paths: ' + tempFilePaths)
|
||
that.pushImg(tempFilePaths)
|
||
wx.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
/**
|
||
* 返回图片信息
|
||
*/
|
||
getImg(getCallback) {
|
||
this._draw(() => {
|
||
wx.canvasToTempFilePath({
|
||
width: this.width * this.export_scale,
|
||
height: Math.round(this.height * this.export_scale),
|
||
destWidth: this.width * this.export_scale,
|
||
destHeight: Math.round(this.height) * this.export_scale,
|
||
fileType: 'png',
|
||
quality: this.quality,
|
||
canvasId: this.el,
|
||
success: (res) => {
|
||
getCallback({
|
||
url: res.tempFilePath,
|
||
width: this.width * this.export_scale,
|
||
height: this.height * this.export_scale
|
||
})
|
||
}
|
||
}, this)
|
||
})
|
||
},
|
||
/**
|
||
* 设置图片动画
|
||
* {
|
||
* x:10,//图片在原有基础上向下移动10px
|
||
* y:10,//图片在原有基础上向右移动10px
|
||
* angle:10,//图片在原有基础上旋转10deg
|
||
* scale:0.5,//图片在原有基础上增加0.5倍
|
||
* }
|
||
*/
|
||
setTransform(transform) {
|
||
if (!transform) return
|
||
if (!this.disable_rotate) {
|
||
this.angle = transform.angle ? this.angle + transform.angle : this.angle
|
||
}
|
||
var scale = this.scale
|
||
if (transform.scale) {
|
||
scale = this.scale + transform.scale
|
||
scale = scale <= this.min_scale ? this.min_scale : scale
|
||
scale = scale >= this.max_scale ? this.max_scale : scale
|
||
}
|
||
this.scale = scale
|
||
let cutX = this.cut_left
|
||
let cutY = this.cut_top
|
||
if (transform.cutX) {
|
||
this.cut_left = cutX + transform.cutX
|
||
}
|
||
if (transform.cutY) {
|
||
this.cut_top = cutY + transform.cutY
|
||
}
|
||
this._img_top = transform.y ? this._img_top + transform.y : this._img_top
|
||
this._img_left = transform.x ? this._img_left + transform.x : this._img_left
|
||
// 图像边缘检测,防止截取到空白
|
||
this._imgMarginDetectionScale()
|
||
// 停止居中裁剪框,继续修改图片位置
|
||
this._moveDuring()
|
||
this.scale = this.scale
|
||
this._img_top = this._img_top
|
||
this._img_left = this._img_left
|
||
|
||
!this._canvas_overflow && this._draw()
|
||
// 可以居中裁剪框了
|
||
this._moveStop()// 结束操作
|
||
},
|
||
/**
|
||
* 设置剪裁框尺寸
|
||
*/
|
||
setCutSize(w, h) {
|
||
this.width = w
|
||
this.height = h
|
||
this._computeCutSize()
|
||
},
|
||
/**
|
||
* 设置剪裁框和图片居中
|
||
*/
|
||
setCutCenter() {
|
||
let cut_top = (this.info.windowHeight - this.height) * 0.5
|
||
let cut_left = (this.info.windowWidth - this.width) * 0.5
|
||
// 顺序不能变
|
||
this._img_top = this._img_top - this.cut_top + cut_top
|
||
this.cut_top = cut_top
|
||
this._img_left = this._img_left - this.cut_left + cut_left
|
||
this.cut_left = cut_left
|
||
},
|
||
_setCutCenter() {
|
||
let cut_top = (this.info.windowHeight - this.height) * 0.5
|
||
let cut_left = (this.info.windowWidth - this.width) * 0.5
|
||
this.cut_top = cut_top
|
||
this.cut_left = cut_left
|
||
},
|
||
/**
|
||
* 设置剪裁框宽度-即将废弃
|
||
*/
|
||
setWidth(width) {
|
||
this.width = width
|
||
this._computeCutSize()
|
||
},
|
||
/**
|
||
* 设置剪裁框高度-即将废弃
|
||
*/
|
||
setHeight(height) {
|
||
this.height = height
|
||
this._computeCutSize()
|
||
},
|
||
/**
|
||
* 是否锁定旋转
|
||
*/
|
||
setDisableRotate(value) {
|
||
this.disable_rotate = value
|
||
},
|
||
/**
|
||
* 是否限制移动
|
||
*/
|
||
setLimitMove(value) {
|
||
this._cut_animation = true
|
||
this.limit_move = !!value
|
||
},
|
||
/**
|
||
* 初始化图片,包括位置、大小、旋转角度
|
||
*/
|
||
imgReset() {
|
||
this.scale = 1
|
||
this.angle = 0
|
||
this.tanLeft = 0
|
||
this.tanTop = 0
|
||
this._img_top = wx.getSystemInfoSync().windowHeight / 2
|
||
this._img_left = wx.getSystemInfoSync().windowWidth / 2
|
||
},
|
||
/**
|
||
* 加载(更换)图片
|
||
*/
|
||
pushImg(src) {
|
||
console.log('pushing img: ' + src)
|
||
if (src) {
|
||
this.imgSrc = src
|
||
// 发现是手动赋值直接返回,交给watch处理
|
||
return
|
||
}
|
||
|
||
wx.getImageInfo({
|
||
src: this.imgSrc,
|
||
success: (res) => {
|
||
console.log('----------------------', res)
|
||
this.imageObject = res
|
||
// 图片非本地路径需要换成本地路径
|
||
if (this.imgSrc.search(/tmp/) == -1) {
|
||
this.imgSrc = res.path
|
||
}
|
||
// 计算最后图片尺寸
|
||
this._imgComputeSize()
|
||
if (this.limit_move) {
|
||
// 限制移动,不留空白处理
|
||
this._imgMarginDetectionScale()
|
||
}
|
||
this._draw()
|
||
},
|
||
fail: (err) => {
|
||
this.imgSrc = ''
|
||
console.log(err)
|
||
}
|
||
})
|
||
},
|
||
/**
|
||
* 设置图片放大缩小
|
||
*/
|
||
setScale(scale) {
|
||
if (!scale) return
|
||
this.scale = scale
|
||
!this._canvas_overflow && this._draw()
|
||
},
|
||
/**
|
||
* 设置图片旋转角度
|
||
*/
|
||
setAngle(angle) {
|
||
if (!angle) return
|
||
this._cut_animation = true
|
||
this.angle = angle
|
||
this._imgMarginDetectionScale()
|
||
!this._canvas_overflow && this._draw()
|
||
},
|
||
_initCanvas() {
|
||
// 初始化canvas
|
||
// if (!this.ctx) {
|
||
let vm = this
|
||
this.ctx = wx.createCanvasContext('image-cropper', this.$wx)
|
||
console.log(this.ctx, '=====')
|
||
// }
|
||
},
|
||
|
||
/**
|
||
* 根据开发者设置的图片目标尺寸计算实际尺寸
|
||
*/
|
||
_initImageSize() {
|
||
// 处理宽高特殊单位 %>px
|
||
if (this.INIT_IMGWIDTH && typeof this.INIT_IMGWIDTH === 'string' && this.INIT_IMGWIDTH.indexOf('%') != -1) {
|
||
let width = this.INIT_IMGWIDTH.replace('%', '')
|
||
this.INIT_IMGWIDTH = this.img_width = this.info.windowWidth / 100 * width
|
||
}
|
||
if (this.INIT_IMGHEIGHT && typeof this.INIT_IMGHEIGHT === 'string' && this.INIT_IMGHEIGHT.indexOf('%') != -1) {
|
||
let height = this.img_height.replace('%', '')
|
||
this.INIT_IMGHEIGHT = this.img_height = this.info.windowHeight / 100 * height
|
||
}
|
||
},
|
||
/**
|
||
* 检测剪裁框位置是否在允许的范围内(屏幕内)
|
||
*/
|
||
_cutDetectionPosition() {
|
||
let _cutDetectionPositionTop = () => {
|
||
// 检测上边距是否在范围内
|
||
if (this.cut_top < 0) {
|
||
this.cut_top = 0
|
||
}
|
||
if (this.cut_top > this.info.windowHeight - this.height) {
|
||
this.cut_top = this.info.windowHeight - this.height
|
||
}
|
||
}, _cutDetectionPositionLeft = () => {
|
||
// 检测左边距是否在范围内
|
||
if (this.cut_left < 0) {
|
||
this.cut_left = 0
|
||
}
|
||
if (this.cut_left > this.info.windowWidth - this.width) {
|
||
this.cut_left = this.info.windowWidth - this.width
|
||
}
|
||
}
|
||
// 裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
|
||
if (this.cut_top == null && this.cut_left == null) {
|
||
this._setCutCenter()
|
||
} else if (this.cut_top != null && this.cut_left != null) {
|
||
_cutDetectionPositionTop()
|
||
_cutDetectionPositionLeft()
|
||
} else if (this.cut_top != null && this.cut_left == null) {
|
||
_cutDetectionPositionTop()
|
||
this.cut_left = (this.info.windowWidth - this.width) / 2
|
||
} else if (this.cut_top == null && this.cut_left != null) {
|
||
_cutDetectionPositionLeft()
|
||
this.cut_top = (this.info.windowHeight - this.height) / 2
|
||
}
|
||
},
|
||
/**
|
||
* 检测canvas位置是否在允许的范围内(屏幕内)如果在屏幕外则不开启实时渲染
|
||
* 如果只写一个参数则另一个默认为0,都不写默认超出屏幕外
|
||
*/
|
||
_canvasDetectionPosition() {
|
||
if (this.canvas_top == null && this.canvas_left == null) {
|
||
this._canvas_overflow = false
|
||
this.canvas_top = -5000
|
||
this.canvas_left = -5000
|
||
} else if (this.canvas_top != null && this.canvas_left != null) {
|
||
if (this.canvas_top < -this.height || this.canvas_top > this.info.windowHeight) {
|
||
this._canvas_overflow = true
|
||
} else {
|
||
this._canvas_overflow = false
|
||
}
|
||
} else if (this.canvas_top != null && this.canvas_left == null) {
|
||
this.canvas_left = 0
|
||
} else if (this.canvas_top == null && this.canvas_left != null) {
|
||
this.canvas_top = 0
|
||
if (this.canvas_left < -this.width || this.canvas_left > this.info.windowWidth) {
|
||
this._canvas_overflow = true
|
||
} else {
|
||
this._canvas_overflow = false
|
||
}
|
||
}
|
||
},
|
||
/**
|
||
* 图片边缘检测-位置
|
||
*/
|
||
_imgMarginDetectionPosition(scale) {
|
||
if (!this.limit_move) return
|
||
let left = this._img_left
|
||
let top = this._img_top
|
||
var scaleV2 = scale || this.scale
|
||
let img_width = this.img_width
|
||
let img_height = this.img_height
|
||
if (this.angle / 90 % 2) {
|
||
img_width = this.img_height
|
||
img_height = this.img_width
|
||
}
|
||
left = this.cut_left + img_width * scaleV2 / 2 >= left ? left : this.cut_left + img_width * scaleV2 / 2
|
||
left = this.cut_left + this.width - img_width * scaleV2 / 2 <= left ? left : this.cut_left + this.width - img_width * scaleV2 / 2
|
||
top = this.cut_top + img_height * scaleV2 / 2 >= top ? top : this.cut_top + img_height * scaleV2 / 2
|
||
top = this.cut_top + this.height - img_height * scaleV2 / 2 <= top ? top : this.cut_top + this.height - img_height * scaleV2 / 2
|
||
this._img_left = left
|
||
this._img_top = top
|
||
this.scale = scaleV2
|
||
},
|
||
/**
|
||
* 图片边缘检测-缩放
|
||
*/
|
||
_imgMarginDetectionScale() {
|
||
if (!this.limit_move) return
|
||
let scale = this.scale
|
||
let img_width = this.img_width
|
||
let img_height = this.img_height
|
||
if (this.angle / 90 % 2) {
|
||
img_width = this.img_height
|
||
img_height = this.img_width
|
||
}
|
||
if (img_width * scale < this.width) {
|
||
scale = this.width / img_width
|
||
}
|
||
if (img_height * scale < this.height) {
|
||
scale = Math.max(scale, this.height / img_height)
|
||
}
|
||
this._imgMarginDetectionPosition(scale)
|
||
},
|
||
/**
|
||
* 计算图片尺寸
|
||
*/
|
||
_imgComputeSize() {
|
||
let img_width = this.img_width,
|
||
img_height = this.img_height
|
||
if (!this.INIT_IMGHEIGHT && !this.INIT_IMGWIDTH) {
|
||
// 默认按图片最小边 = 对应裁剪框尺寸
|
||
img_width = this.imageObject.width
|
||
img_height = this.imageObject.height
|
||
if (img_width / img_height > this.width / this.height) {
|
||
img_height = this.height
|
||
img_width = this.imageObject.width / this.imageObject.height * img_height
|
||
} else {
|
||
img_width = this.width
|
||
img_height = this.imageObject.height / this.imageObject.width * img_width
|
||
}
|
||
} else if (this.INIT_IMGHEIGHT && !this.INIT_IMGWIDTH) {
|
||
img_width = this.imageObject.width / this.imageObject.height * this.INIT_IMGHEIGHT
|
||
} else if (!this.INIT_IMGHEIGHT && this.INIT_IMGWIDTH) {
|
||
img_height = this.imageObject.height / this.imageObject.width * this.INIT_IMGWIDTH
|
||
}
|
||
console.log(img_width)
|
||
console.log(img_height)
|
||
this.img_width = img_width
|
||
this.img_height = img_height
|
||
},
|
||
// 改变截取框大小
|
||
_computeCutSize() {
|
||
if (this.width > this.info.windowWidth) {
|
||
this.width = his.info.windowWidth
|
||
} else if (this.width + this.cut_left > this.info.windowWidth) {
|
||
this.cut_left = this.info.windowWidth - this.cut_left
|
||
}
|
||
if (this.height > this.info.windowHeight) {
|
||
this.height = this.info.windowHeight
|
||
} else if (this.height + this.cut_top > this.info.windowHeight) {
|
||
this.cut_top = this.info.windowHeight - this.cut_top
|
||
}
|
||
!this._canvas_overflow && this._draw()
|
||
},
|
||
|
||
_move_throttle() {
|
||
// 安卓需要节流
|
||
if (this.info.platform == 'android') {
|
||
clearTimeout(this.MOVE_THROTTLE)
|
||
this.MOVE_THROTTLE = setTimeout(() => {
|
||
this.MOVE_THROTTLE_FLAG = true
|
||
}, 1000 / 40)
|
||
return this.MOVE_THROTTLE_FLAG
|
||
} else {
|
||
this.MOVE_THROTTLE_FLAG = true
|
||
}
|
||
},
|
||
|
||
// 停止移动时需要做的操作
|
||
_moveStop() {
|
||
// 清空之前的自动居中延迟函数并添加最新的
|
||
clearTimeout(this.TIME_CUT_CENTER)
|
||
this.TIME_CUT_CENTER = setTimeout(() => {
|
||
// 动画启动
|
||
if (!this._cut_animation) {
|
||
this._cut_animation = true
|
||
}
|
||
this.setCutCenter()
|
||
}, 1000)
|
||
// 清空之前的背景变化延迟函数并添加最新的
|
||
clearTimeout(this.TIME_BG)
|
||
this.TIME_BG = setTimeout(() => {
|
||
if (this._flag_bright) {
|
||
this._flag_bright = false
|
||
}
|
||
}, 2000)
|
||
},
|
||
// 移动中
|
||
_moveDuring() {
|
||
// 清空之前的自动居中延迟函数
|
||
clearTimeout(this.TIME_CUT_CENTER)
|
||
// 清空之前的背景变化延迟函数
|
||
clearTimeout(this.TIME_BG)
|
||
// 高亮背景
|
||
if (!this._flag_bright) {
|
||
this._flag_bright = true
|
||
}
|
||
}
|
||
}
|
||
})
|
||
</script>
|
||
<style lang="less">
|
||
.main-box{
|
||
width: 100%;
|
||
height: 10vh;
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
z-index: 999999;
|
||
padding: 0 10vw;
|
||
.main-cancel,.main-save{
|
||
background: #d1d1d1;
|
||
padding: 8rpx 0;
|
||
width: 200rpx;
|
||
border-radius: 6rpx;
|
||
color: #D92553;
|
||
}
|
||
.main-save{
|
||
color: white;
|
||
background: #D92553;
|
||
}
|
||
}
|
||
.image-cropper{
|
||
background:rgba(14, 13, 13,.8);
|
||
position: fixed;
|
||
top:0;
|
||
left:0;
|
||
width:100vw;
|
||
height:100vh;
|
||
z-index: 1;
|
||
}
|
||
.main{
|
||
position: absolute;
|
||
width:100vw;
|
||
height:100vh;
|
||
overflow: hidden;
|
||
}
|
||
.content{
|
||
z-index: 9;
|
||
position: absolute;
|
||
width:100vw;
|
||
height:100vh;
|
||
display: flex;
|
||
flex-direction:column;
|
||
pointer-events:none;
|
||
}
|
||
.bg_black{
|
||
background: rgba(0, 0, 0, 0.8)!important;
|
||
}
|
||
.bg_gray{
|
||
background: rgba(0, 0, 0, 0.45);
|
||
transition-duration: .35s;
|
||
}
|
||
.content>.content_top{
|
||
pointer-events:none;
|
||
}
|
||
.content>.content_middle{
|
||
display: flex;
|
||
height: 200px;
|
||
width:100%;
|
||
}
|
||
.content_middle_middle{
|
||
width:200px;
|
||
box-sizing:border-box;
|
||
position: relative;
|
||
transition-duration: .3s;
|
||
}
|
||
.content_middle_right{
|
||
flex: auto;
|
||
}
|
||
.content>.content_bottom{
|
||
flex: auto;
|
||
}
|
||
.image-cropper .img{
|
||
z-index: 2;
|
||
top:0;
|
||
left:0;
|
||
position: absolute;
|
||
border:none;
|
||
width:100%;
|
||
backface-visibility: hidden;
|
||
transform-origin:center;
|
||
}
|
||
.image-cropper-canvas{
|
||
position: fixed;
|
||
background: white;
|
||
width:150px;
|
||
height:150px;
|
||
z-index: 10;
|
||
top:-200%;
|
||
pointer-events:none;
|
||
}
|
||
.border{
|
||
background: white;
|
||
pointer-events:auto;
|
||
position:absolute;
|
||
}
|
||
.border-top-left{
|
||
left:-2.5px;
|
||
top:-2.5px;
|
||
height:2.5px;
|
||
width:33rpx;
|
||
}
|
||
.border-top-right{
|
||
right:-2.5px;
|
||
top:-2.5px;
|
||
height:2.5px;
|
||
width:33rpx;
|
||
}
|
||
.border-right-top{
|
||
top:-1px;
|
||
width:2.5px;
|
||
height:30rpx;
|
||
right:-2.5px;
|
||
}
|
||
.border-right-bottom{
|
||
width:2.5px;
|
||
height:30rpx;
|
||
right:-2.5px;
|
||
bottom:-1px;
|
||
}
|
||
.border-bottom-left{
|
||
height:2.5px;
|
||
width:33rpx;
|
||
bottom:-2.5px;
|
||
left:-2.5px;
|
||
}
|
||
.border-bottom-right{
|
||
height:2.5px;
|
||
width:33rpx;
|
||
bottom:-2.5px;
|
||
right:-2.5px;
|
||
}
|
||
.border-left-top{
|
||
top:-1px;
|
||
width:2.5px;
|
||
height:30rpx;
|
||
left:-2.5px;
|
||
}
|
||
.border-left-bottom{
|
||
width:2.5px;
|
||
height:30rpx;
|
||
left:-2.5px;
|
||
bottom:-1px;
|
||
}
|
||
</style>
|
||
<config>
|
||
{
|
||
usingComponents: {
|
||
chooseImageTips: '~@/components/chooseImageTips',
|
||
}
|
||
}
|
||
</config>
|