项目需要一个添加多张图片再把图片url传给后台的组件(嘛,照片选取用ImagePicker就好啦)大体样子如下
主要问题是在使用七牛取到url之后的存取问题
下面主要讨论使用ImagePicker换行时browse_button对应id出现的问题。另外说一下移动端如何让id对应按钮直接调起相机以及图片压缩的方法。(使用七牛js版本为1.x,静态文件方式引入,antd-mobile使用2.x)
七牛官方文档 plupload使用指南
componentDidMount(){
let _this = this;
let imgBox = document.getElementsByClassName(this.props.name);
imgBox[0].getElementsByTagName("input")[0].setAttribute('id',this.props.inputID);
imgBox[0].getElementsByTagName("input")[0].addEventListener('onporpertychange',this.onChange);
var Qiniu1 = new QiniuJsSDK();
var commonOption={
runtimes: 'html5,flash,html4', // 上传模式,依次退化
uptoken_url: baseURL+'free/getQiNiuToken', // Ajax 请求 uptoken 的 Url,**强烈建议设置**(服务端提供)
get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的 uptoken
unique_names: true, // 默认 false,key 为文件名。若开启该选项,JS-SDK 会为每个文件自动生成key(文件名)
domain: 'image.xxxxxx.com', // bucket 域名,下载资源时用到,如:'http://xxx.bkt.clouddn.com/' **必需**
auto_start: true // 选择文件后自动上传,若关闭需要自己绑定事件触发上传,
}
var init1={
init:{
'FilesAdded': function (up, files) {
// 设置预览图地址
},
'FileUploaded': function (up, file, info) {
var domain = up.getOption('domain');
var res = JSON.parse(info);
var sourceLink = "http://"+domain+"/"+res.key;//目标地址
console.info(sourceLink);
_this.props.saveImg(_this.props.name,sourceLink)
},
'Error': function(up, err, errTip) {
//上传出错时,处理相关的事情
console.log(err);
},
'Key': function (up, file) {
var key = "";
return key
}
}
}
var aimId1={browse_button: this.props.inputID};
var option1 = Object.assign(commonOption, init1,aimId1);
var uploader1 = Qiniu1.uploader(option1);
}
看起来是没有问题,给input标签一个id,通过此id上传、获取七牛返回的地址再进行显示,但实际情况会出现两个问题
1.换行后图片上传失败
2.ImagePicker限制图片张数(不显示添加按钮)添加最后一张后删除任一张图片再进行上传失效
先找找原因
imgBox[0].getElementsByTagName("input")[0].setAttribute('id',this.props.inputID);
如果你看过imagepicker里添加按钮的input标签后,你会发现在每次添加图片后此id会保留(即每次添加图片这个按钮会往后移一位),当然有两种情况会重新生成input标签(1换行2删掉最后一张照片)这两种情况下input标签下没有id,昂这个简单把componentDidMount换成componentDidUpdate是不是就行了(不行哦会有问题)
换行后
那好,针对这两种情况做下处理
let imgBox = document.getElementsByClassName(this.props.name);
let num = imgBox[0].getElementsByClassName('am-image-picker-list')[0].childNodes.length;
if(this.state.rowNum !== num){ //用于判断第一种情况
this.setState({rowNum:num});
this.onLoadImg();
}
else if (this.state.isLastPosition){ //用于判断第二种情况
this.onLoadImg();
}
解决后的代码:
export default class extends React.Component{
constructor(props){
super(props);
this.state={
rowNum:1,
isLastPosition:false,//如果是已上传到最后一张再删除会因为input没赋id导致无法上传七牛
};
}
componentDidMount(){
this.onLoadImg();
}
componentDidUpdate(){
let imgBox = document.getElementsByClassName(this.props.name);
let num = imgBox[0].getElementsByClassName('am-image-picker-list')[0].childNodes.length; //获取行数
if(this.state.rowNum !== num){
this.setState({rowNum:num});
this.onLoadImg();
}
else if (this.state.isLastPosition){
this.onLoadImg();
}
}
onLoadImg =()=>{
let _this = this;
let imgBox = document.getElementsByClassName(this.props.name);
console.log(imgBox[0]);
if(imgBox[0].getElementsByTagName("input")[0] !==undefined){
imgBox[0].getElementsByTagName("input")[0].setAttribute('id',`${_this.props.inputID}`);
imgBox[0].getElementsByTagName("input")[0].addEventListener('onporpertychange',this.onChange);
var Qiniu = new QiniuJsSDK();
var commonOption={
runtimes: 'html5,flash,html4', // 上传模式,依次退化
uptoken_url: baseURL+'free/getQiNiuToken', // Ajax 请求 uptoken 的 Url,**强烈建议设置**(服务端提供)
get_new_uptoken: false, // 设置上传文件的时候是否每次都重新获取新的 uptoken
unique_names: true, // 默认 false,key 为文件名。若开启该选项,JS-SDK 会为每个文件自动生成key(文件名)
domain: 'image.quantahelp.com', // bucket 域名,下载资源时用到,如:'http://xxx.bkt.clouddn.com/' **必需**
auto_start: true // 选择文件后自动上传,若关闭需要自己绑定事件触发上传,
}
var init={
init:{
'FilesAdded': function (up, files) {
// 设置预览图地址
},
'FileUploaded': function (up, file, info) {
var domain = up.getOption('domain');
var res = JSON.parse(info);
var sourceLink = "http://"+domain+"/"+res.key;//目标地址
console.info(sourceLink);
_this.props.saveImg(_this.props.name,sourceLink)
},
'Error': function(up, err, errTip) {
//上传出错时,处理相关的事情
console.log(err);
},
'Key': function (up, file) {
var key = "";
return key
}
}
};
var aimId={browse_button: `${_this.props.inputID}`};
var option = Object.assign(commonOption, init,aimId);
var uploader = Qiniu.uploader(option);
}
};
onChange =key=> (files, type, index) => {
if(type=='remove'){ //删除图片
this.props.removeImg(key,files,index)
}
};
onDeleteChange =key=> (files, type, index) => {
if(type=='remove'){ //删除图片
this.props.removeImg(key,files,index);
console.log(this.props.files.length);
if (files.length ===this.props.num-1){
// this.isLastPosition =true
this.setState({isLastPosition:true})
}else {
this.setState({isLastPosition:false})
}
}else {
this.setState({isLastPosition:false})
}
};
render(){
// this.isLastPosition =false;
const { files } = this.props;
return(
)
}
}
在说怎么调起相机之前,先了解一下七牛如何通过给browse_button一个id或元素就使其调起照片选择的。这里先给任意标签一个id='idImg1',让browse_button使用此id。看下网页生成的布局
这样看就清楚了,当我们对应id后,会在当前标签所在层级最后生成一个div标签覆盖在id对应的标签上并且此标签子元素是一个input,通过此来调起照片选择。那么想要调起相机只需要更改input中部分属性即可。代码如下
这里还要注意这个标签的生成时间,我是在componentDidMount中执行七牛的方法但这个div标签生成却是在此周期执行完后,所以要想通过下面代码修改真实DOM就一定要确保此标签以生成。(我是通过在DidMount中使用setTimeout延时2s再执行代码来解决的,因为实在找不到监听此标签生成的办法。_(:3」∠))
let camera = document.getElementById('idImg1');
if (camera.nextSibling.nextSibling){
camera.nextSibling.nextSibling.firstChild.setAttribute('capture','camera');
camera.nextSibling.nextSibling.firstChild.setAttribute('accept','image/*');
camera.nextSibling.nextSibling.firstChild.removeAttribute('multiple')
}
这个建议参考一下此文章
在commonOption中添加此属性即可是实现图片压缩
resize: {
crop: true,
quality: 60,
preserve_headers: false
}
完整代码 这里 (token获取方式请自己添加,此项目并未引入七牛库,请在自己项目中测试)