import { defineComponent } from 'vue' import 'vue-cropper/dist/index.css' import { VueCropper } from 'vue-cropper' import styles from './index.module.less' export default defineComponent({ name: 'o-cropper', components: { VueCropper }, props: { hideInput: { type: Boolean, default: false }, option: { type: Object }, onCancelTailor: { type: Function, default: () => {} }, // 取消 getBase64Data: { type: Function, default: () => {} }, getBlob: { type: Function, default: () => {} }, getFile: { type: Function, default: () => {} }, imgOriginF: { type: Function, default: () => {} } }, data() { return { img: '', config: { ceilbutton: false, //顶部按钮,默认底部 outputSize: 1, //裁剪生成图片的质量 outputType: 'png', //裁剪生成图片的格式,默认png info: false, //裁剪框的大小信息 canScale: true, //图片是否允许滚轮缩放 autoCrop: false, //是否默认生成截图框 autoCropWidth: 0, //默认生成截图框宽度 autoCropHeight: 0, //默认生成截图框高度 fixed: true, //是否开启截图框宽高固定比例 fixedNumber: [1, 1], //截图框的宽高比例 full: false, //是否输出原图比例的截图 fixedBox: true, //固定截图框大小 不允许改变 canMove: true, //上传图片是否可以移动 canMoveBox: false, //截图框能否拖动 original: false, //上传图片按照原始比例渲染 centerBox: true, //截图框是否被限制在图片里面 high: true, //是否按照设备的dpr 输出等比例图片 infoTrue: false, //true 为展示真实输出图片宽高 false 展示看到的截图框宽高 maxImgSize: 2000, //限制图片最大宽度和高度 enlarge: 1, //图片根据截图框输出比例倍数 mode: '100%', //图片默认渲染方式 cancelButtonText: '取消', //取消按钮文本 confirmButtonText: '确定', //确定按钮文本 cancelButtonBackgroundColor: '#606266', //取消按钮背景色 confirmButtonBackgroundColor: '#ed594c', //确定按钮背景色 cancelButtonTextColor: '#ffffff', //取消按钮字体色 confirmButtonTextColor: '#ffffff' //确定按钮字体色 } } }, mounted() { this.config = Object.assign(this.config, this.option) }, methods: { //添加网格线 addSlide() { if (document.getElementById('vertical') == null) { const box = document.getElementsByClassName('cropper-crop-box')[0] //左网格线 const verticalLeft = document.createElement('div') verticalLeft.id = 'vertical' verticalLeft.style.width = '1px' verticalLeft.style.height = '100%' verticalLeft.style.top = '0px' verticalLeft.style.left = '33%' verticalLeft.style.position = 'absolute' verticalLeft.style.backgroundColor = '#fff' verticalLeft.style.zIndex = '522' verticalLeft.style.opacity = '0.5' //右网格线 const verticalRight = document.createElement('div') verticalRight.style.width = '1px' verticalRight.style.height = '100%' verticalRight.style.top = '0px' verticalRight.style.right = '33%' verticalRight.style.position = 'absolute' verticalRight.style.backgroundColor = '#fff' verticalRight.style.zIndex = '522' verticalRight.style.opacity = '0.5' //上网格线 const verticalTop = document.createElement('div') verticalTop.style.width = '100%' verticalTop.style.height = '1px' verticalTop.style.top = '33%' verticalTop.style.left = '0px' verticalTop.style.position = 'absolute' verticalTop.style.backgroundColor = '#fff' verticalTop.style.zIndex = '522' verticalTop.style.opacity = '0.5' //下网格线 const verticalBottom = document.createElement('div') verticalBottom.style.width = '100%' verticalBottom.style.height = '1px' verticalBottom.style.bottom = '33%' verticalBottom.style.left = '0px' verticalBottom.style.position = 'absolute' verticalBottom.style.backgroundColor = '#fff' verticalBottom.style.zIndex = '522' verticalBottom.style.opacity = '0.5' //左上边线 const LeftTopSide = document.createElement('div') LeftTopSide.style.width = '30px' LeftTopSide.style.height = '4px' LeftTopSide.style.top = '-4px' LeftTopSide.style.left = '-4px' LeftTopSide.style.position = 'absolute' LeftTopSide.style.backgroundColor = '#fff' LeftTopSide.style.zIndex = '522' LeftTopSide.style.opacity = '1' //上左边线 const TopListSide = document.createElement('div') TopListSide.style.width = '4px' TopListSide.style.height = '30px' TopListSide.style.top = '-4px' TopListSide.style.left = '-4px' TopListSide.style.position = 'absolute' TopListSide.style.backgroundColor = '#fff' TopListSide.style.zIndex = '522' TopListSide.style.opacity = '1' //右上边线 const RightTopSide = document.createElement('div') RightTopSide.style.width = '30px' RightTopSide.style.height = '4px' RightTopSide.style.top = '-4px' RightTopSide.style.right = '-4px' RightTopSide.style.position = 'absolute' RightTopSide.style.backgroundColor = '#fff' RightTopSide.style.zIndex = '522' RightTopSide.style.opacity = '1' //上右边线 const TopRightSide = document.createElement('div') TopRightSide.style.width = '4px' TopRightSide.style.height = '30px' TopRightSide.style.top = '-4px' TopRightSide.style.right = '-4px' TopRightSide.style.position = 'absolute' TopRightSide.style.backgroundColor = '#fff' TopRightSide.style.zIndex = '522' TopRightSide.style.opacity = '1' //左下边线 const LeftBottomSide = document.createElement('div') LeftBottomSide.style.width = '30px' LeftBottomSide.style.height = '4px' LeftBottomSide.style.bottom = '-4px' LeftBottomSide.style.left = '-4px' LeftBottomSide.style.position = 'absolute' LeftBottomSide.style.backgroundColor = '#fff' LeftBottomSide.style.zIndex = '522' LeftBottomSide.style.opacity = '1' //下左边线 const BottomListSide = document.createElement('div') BottomListSide.style.width = '4px' BottomListSide.style.height = '30px' BottomListSide.style.bottom = '-4px' BottomListSide.style.left = '-4px' BottomListSide.style.position = 'absolute' BottomListSide.style.backgroundColor = '#fff' BottomListSide.style.zIndex = '522' BottomListSide.style.opacity = '1' //右下边线 const RightBottomSide = document.createElement('div') RightBottomSide.style.width = '30px' RightBottomSide.style.height = '4px' RightBottomSide.style.bottom = '-4px' RightBottomSide.style.right = '-4px' RightBottomSide.style.position = 'absolute' RightBottomSide.style.backgroundColor = '#fff' RightBottomSide.style.zIndex = '522' RightBottomSide.style.opacity = '1' //下右边线 const BottomRightSide = document.createElement('div') BottomRightSide.style.width = '4px' BottomRightSide.style.height = '30px' BottomRightSide.style.bottom = '-4px' BottomRightSide.style.right = '-4px' BottomRightSide.style.position = 'absolute' BottomRightSide.style.backgroundColor = '#fff' BottomRightSide.style.zIndex = '522' BottomRightSide.style.opacity = '1' //一起生成 box.appendChild(verticalLeft) box.appendChild(verticalRight) box.appendChild(verticalTop) box.appendChild(verticalBottom) box.appendChild(LeftTopSide) box.appendChild(TopListSide) box.appendChild(RightTopSide) box.appendChild(TopRightSide) box.appendChild(LeftBottomSide) box.appendChild(BottomListSide) box.appendChild(RightBottomSide) box.appendChild(BottomRightSide) } }, //异步onload图片 onLoadImg(photoUrl: any) { return new Promise(function (resolve, reject) { const reader = new FileReader() reader.readAsDataURL(photoUrl) reader.onload = (e: any) => { resolve(e.target['result']) } }) }, /** * 载入文件 * template: * * * javascript: * this.$refs.cropper.loadFile() * * @param file */ loadFile(file: any) { if (file instanceof File) { this.onLoadImg(file).then((base64: any) => { this.img = base64 setTimeout(() => { this.config.autoCrop = true this.addSlide() }, 10) }) } else { throw new Error('Arguments file is not File') } }, /** * * @param base64 */ loadBase64(base64: string) { if (typeof base64 !== 'string') { throw new Error('Arguments base64 is not string') } const base = base64.split(',') if (!/^data:image\/(.*?);base64$/.test(base[0])) { throw new Error('Arguments base64 MIME is not image/*') } // Base64 Regex @see https://learnku.com/articles/42295 if (!/^[\/]?([\da-zA-Z]+[\/+]+)*[\da-zA-Z]+([+=]{1,2}|[\/])?$/.test(base[1])) { throw new Error('Not standard base64') } this.img = base64 setTimeout(() => { this.config.autoCrop = true this.addSlide() }, 10) }, rotating(e: any) { ;(this as any).$refs.cropper.rotateRight() // document.getElementsByClassName("cropper-modal")[0].style = "background-color: rgba(0,0,0,0.5);transition: 0.88s"; }, canceltailor() { this.img = '' this.onCancelTailor() }, tailoring() { // 获取截图的base64数据 ;(this as any).$refs.cropper.getCropData((data: any) => { this.getBase64Data(data) this.getBlob(data) this.img = '' this.config.autoCrop = false }) // 获取截图的blob数据 ;(this as any).$refs.cropper.getCropBlob((data: BlobPart) => { this.getBase64Data(data) this.getBlob(data) // Blob 转 File const suffix = { jpeg: 'jpg', png: 'png', webp: 'webp' }[this.config.outputType] const time = new Date().getTime() const file = new File([data], `${time}.${suffix}`, { type: `image/${this.config.outputType}` }) this.getFile(file) this.img = '' this.config.autoCrop = false }) }, async upPhoto(e: any) { let photoUrl = e.target.files[0] ;(this as any).$refs.headInput.value = null if (photoUrl != undefined) { this.imgOriginF(photoUrl) this.img = (await this.onLoadImg(photoUrl)) as string this.config.autoCrop = true setTimeout(() => { this.addSlide() }, 20) } }, onCropMoving(e: any) { // console.log('onCropMoving') }, onImgMoving(e: any) { // console.log('onCropMoving') } }, render() { return (
{this.hideInput} {!this.hideInput ? ( ) : null} {this.img != '' ? (
{this.config.ceilbutton ? (
{this.config.cancelButtonText}
{this.config.confirmButtonText}
) : null}
{!this.config.ceilbutton ? (
{this.config.cancelButtonText}
{this.config.confirmButtonText}
) : null}
) : null}
) } })