import './upload.css'; import { Component, createRef, Fragment } from "react"; import { apis } from '../../helper/apis'; import Spinner from '../Spinner/Spinner'; export default class UploadUnit extends Component { imgRef = createRef(); imgWidth; imgHeight; constructor(props) { super(props); this.state = { // 0: loading, 1: compressing, 2: compressed, 3: uploading, 4: uploaded status: -1, src: null, file: null, progress: 0, width: 0, isScaled: false, transform: '' }; this.upload = this.upload.bind(this); this.handleCancel = this.handleCancel.bind(this); this.scale = this.scale.bind(this); this.unscale = this.unscale.bind(this); } componentDidMount() { setTimeout(() => { this.readFile(this.props.file); }, 100); } componentDidUpdate() { if (this.props.upload && this.state.status === 2) this.upload(); } handleCancel() { this.setState({ status: -1 }); setTimeout(() => { this.props.onCancel(); }, 300); } readFile(file) { if (!["image/jpeg", "image/png", "image/gif"].includes(file.type)) { alert('请不要上传jpg、png、gif格式以外的文件!'); this.handleCancel(); return; } let reader = new FileReader(); this.setState({ status: -2 }); setTimeout(() => { this.setState({ status: 0 }); reader.onload = () => { var image = new Image(); // 被注释掉的是用来应对ios巨大图片没来得及加载的问题 // image.onload = () => setTimeout(() => this.convert(image), 1000); image.onload = () => this.convert(image); image.src = reader.result; this.setState({ status: 1 }); }; reader.readAsDataURL(file); }, 300); } convert(img) { if (this.converted) return; var canvas = document.createElement('canvas'); var { width, height } = img; if (width > 1600) { height *= 1600 / width; width = 1600; } if (height > 1200) { width *= 1200 / height; height = 1200; } canvas.width = width; canvas.height = height; this.imgWidth = width; this.imgHeight = height; canvas.getContext('2d').drawImage(img, 0, 0, width, height); canvas.toBlob(blob => { this.setState({ src: canvas.toDataURL('image/jpeg', 1), status: 2, file: blob, width: width / height * 200 }); }, 'image/jpeg', 1); } async upload() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { var data = JSON.parse(xhr.responseText); if (data.code === 200) { this.setState({ status: 4 }); this.props.onUpload(data.data.url); } else { this.setState({ status: 2 }); this.props.onUploadError(data.msg); } } else { this.setState({ status: 2 }); this.props.onUploadError('上传失败:服务器出错'); } } }; xhr.onerror = () => { this.setState({ status: 2 }); this.props.onUploadError('请求失败,请检查网络'); } xhr.onprogress = e => { if (e.lengthComputable) { var percent = Math.round(e.loaded * 100 / e.total); this.setState({ progress: percent }); } }; xhr.open("POST", apis.uploadImage, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); var fd = new FormData(); fd.append("image", this.state.file, 'image.jpg'); xhr.send(fd); this.setState({ status: 3, progress: 0 }); } scale() { if (this.state.isScaled) return; let el = this.imgRef.current; let { x, y } = el.getBoundingClientRect(); let { innerWidth, innerHeight } = window; console.log(x, y, innerWidth, innerHeight); let initialScale = 200 / this.imgHeight, terminalScale = Math.min(1, Math.min(innerWidth / this.imgWidth, innerHeight / this.imgHeight)); this.setState({ transform: `translate(${x - (innerWidth - this.imgWidth * terminalScale) / 2}px, ${y - (innerHeight - this.imgHeight * terminalScale) / 2}px) scale(${initialScale})`, isScaled: true }); setTimeout(() => { this.setState({ transform: `translate(0, 0) scale(${terminalScale})` }); }, 0); } unscale() { if (!this.state.isScaled) return; let el = this.imgRef.current; let { x, y } = el.getBoundingClientRect(); let { innerWidth, innerHeight } = window; let initialScale = 200 / this.imgHeight, terminalScale = Math.min(1, Math.min(innerWidth / this.imgWidth, innerHeight / this.imgHeight)); this.setState({ transform: `translate(${x - (innerWidth - this.imgWidth * terminalScale) / 2}px, ${y - (innerHeight - this.imgHeight * terminalScale) / 2}px) scale(${initialScale})`, isScaled: true }); setTimeout(() => { this.setState({ isScaled: false }); }, 300); } render() { const angle = this.state.progress / 100 * Math.PI * 2; console.log(this.state.transform); return (