需求是编写一个头像剪裁工具再封装成为一个组件,然后根据功能开始逐步编写代码:先是上传图片 => 预览图片 => 编辑图片。
刚开始没有去考虑兼容性的问题,直接编写upload部分的代码,参考了很多代码还有HTML5 FILE API之后,发现很少有React编写的这样的代码,因为想简单一点,所以直接就使用
let file = e.target.files[0];
let url = window.URL.createObjectURL(file);
console.info(url);
打印出来的结果是:
blob:http://localhost:3001/396d3dbb-be52-4fd4-aaf9-50c0c04ecef9
这个是个DOMString类型的返回值,根据MDN:
A DOMString containing an object URL that can be used to reference the contents of the specified source object.
然后我想使用canvas去加载这个文件再对这个文件做裁剪的操作,问题就来了,ctx.drawImage(img)不能直接去解析到这个DOMString再加载出来,后来网上发现确实要先转化成dataURL才能被正常加载,然后就一直尝试这样的方案:
reader.readAsDataURL(file);
会报错:
Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob
无法被FileReader.readAsDataURL()顺利转换,最后看了些stackoverflow上的方案,综合了一下。
代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e){
console.info(url);
if (window.FileReader){
console.info("Support file reader");
let file = e.target.files[0];
let reader = new FileReader();
let img = new Image();
if(file && file.type.match('image.*')){
reader.readAsDataURL(file);
}else{
console.info('Not match!')
}
reader.onload = e => {
let ctx = this.canvas.getContext('2d');
img.src = reader.result;
ctx.drawImage(img,10,10);
}
}
}
render(){
return <div>
<input type="file" multiple onChange={this.handleChange}/>
<canvas width="500px"
height="500px"
style={{border:"solid 1px lightgrey"}}
ref={canvas=>this.canvas = canvas}/>
</div>
}
}
ReactDOM.render(<App/>,document.getElementById('root'));