上传图片:
赞
踩
<template> <div class="hello"> <div class="avator"> <div class="fileUPLoad" style="display: flex; align-items: center"> <p class="crop-dialog-label" style="width: 90px">上传图片:</p> <a-upload name="avatar" list-type="picture-card" class="avatar-uploader" :show-upload-list="false" :before-upload="beforeUpload" @change="handleChange" > <span class="selectBtn">选择图片</span> </a-upload> </div> <p class="crop-dialog-limit-info"> 图片格式只支持:BMP、JPEG、JPG、PNG, 大小不超过2M </p> <div class="showing"> <div class="img"> <img ref="image" :src="picUrl" alt="请上传头像" /> </div> <div class="res" style="margin-left: 60px"> <p>头像预览</p> <div class="before"></div> <div class="before round"></div> </div> </div> </div> <a-button @click="sureSava">裁剪</a-button> </div> </template>
<script lang="ts"> import { defineComponent, onMounted, ref, useStore, } from '@nuxtjs/composition-api' import Cropper from 'cropperjs' import 'cropperjs/dist/cropper.css' import { message } from 'ant-design-vue' import { uploadFile } from '~/api/file' import useAxios from '~/hooks/useAxios' import { postUpdateUserInfo } from '~/api/user' import { FullState } from '~/store/types' interface fileObj { lastModified: number name: string size: number type: string uid: string webkitRelativePath: string originFileObj: File percent: number response: string status: string } interface uploadDone { fileFullName: string staticDomain: string } function getBase64(img: any, callback: any) { const reader = new FileReader() reader.addEventListener('load', () => callback(reader.result)) reader.readAsDataURL(img) } export default defineComponent({ name: 'HelloWorld', setup() { const myCropper = ref<any>() const afterImg = ref<any>('') const image = ref<any>() const init = () => { myCropper.value = new Cropper(image.value, { autoCropArea: 0.8, // 可设置裁剪框的范围,为1则是与整个裁剪区域一样大 dragMode: 'none', initialAspectRatio: 1, aspectRatio: 1, preview: '.before', background: false, zoomOnWheel: true, viewMode: 1, }) } // 裁剪 const sureSava = () => { // 裁剪之后的图片 afterImg.value = myCropper.value .getCroppedCanvas({ imageSmoothingQuality: 'high', }) .toDataURL(imgInfo.type) } onMounted(() => { // 初始化画布不能放在 beforeUpload 方法中,因为upload上传图片时会多次调用,就会造成初始化多个画布,页面也显示多个 init() }) const store = useStore<FullState>() const $axios = useAxios() const picUrl = ref<string>('') let imgInfo: File const handleChange = (info: any) => { if (standard) { imgInfo = info.file.originFileObj getBase64(info.file.originFileObj, (imageUrl: any) => { picUrl.value = imageUrl }) // 更新cavas画布上的图片 myCropper.value.replace(picUrl.value) } } // 图片是否符合要求 let standard = false const beforeUpload = (file: fileObj) => { const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp' if (!isJpgOrPng) { message.error('请重新选择图片格式') } const isLt2M = file.size / 1024 / 1024 < 2 if (!isLt2M) { message.error('图片过大!') } return (standard = isJpgOrPng && isLt2M) } const uploadImg = () => { try { const formdata = new FormData() formdata.append('appId', 'aiKnowledge') formdata.append('businessType', '') formdata.append('type', 'avatar') formdata.append('fileName', imgInfo.name) // ===裁剪后file对象向后台传递的第一种方法 // function data2blob(data: string, mime: string) { // data = data.split(',')[1] // data = window.atob(data) // const ia = new Uint8Array(data.length) // for (let i = 0; i < data.length; i++) { // ia[i] = data.charCodeAt(i) // } // // canvas.toDataURL 返回的默认格式就是 image/png // return new Blob([ia], { // type: mime, // }) // } // formdata.append( // 'file', // data2blob(afterImg.value, imgInfo.type), // imgInfo.name // ) // ===裁剪后file对象向后台传递的第二种方法 接口必须写在myCropper.value.getCroppedCanvas().toBlob() 函数体内 JS 执行机制会先调接口 后执行此函数 这样接口就缺失file参数 myCropper.value.getCroppedCanvas().toBlob(async (blob: Blob) => { // 必须传递第三个参数(上传文件的名字),否则file参数会有误 导致接口调不通 formdata.append('file', blob, imgInfo.name) const res: uploadDone = await uploadFile($axios, formdata) const params = { appId: 'aiKnowledge', avatarUrl: res.staticDomain + '/' + res.fileFullName, } await postUpdateUserInfo($axios, params) store.commit('user/UPDATE_AVATAR', params.avatarUrl) myCropper() }) } catch (error) {} } const handleCancel = () => { picUrl.value = '' // 关闭弹框注销画布 myCropper.value.destroy() } return { image, afterImg, sureSava, handleChange, uploadImg, beforeUpload, picUrl, handleCancel, } }, }) </script>
<style lang="less" scoped> /deep/span.ant-upload:hover { background-color: #1f71e0; .selectBtn { color: #fff; } } .avator { margin-bottom: 16px; .showing { display: flex; .img { width: 280px; height: 280px; background-color: #ccc; img { width: 100%; height: 100%; } } .before { background-color: #ccc; width: 80px !important; height: 80px !important; overflow: hidden; img { width: 80px !important; height: 80px !important; border-radius: 4px; } } .round { margin-top: 30px; border-radius: 50%; img { border-radius: 50%; } } } } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。