自定义React图片上传组件

现在网上有很多封装好的插件,但是我没有找到适合我们项目需求的,所以自定义封装了这个图片上传组件。该组件是基于React设计的,希望对你有帮助。你也可以去https://github.com/windSandEye/img-upload/tree/master下载我的源码。

属性名 说明 类型 默认值 可选值
imgTitle 组件的中文描述 String “”
height 图片外框的高度 String 200px
renderState 图片初始化状态 String init init,loading,upload
imgSrc 图片src路径 String “”
titleClass 文本描述信息的样式 String “”
disabled 是否禁用组件 Boolean false true或false
accept 接受的图片类型 String “*” jpg,png,gif等


事件 说明 参数 返回值
getImgFile 获取图片文件信息 {file:图片文件,src:图片src}
resetImgSrc 重置图片信息


import React from 'react';
import { Icon, Modal } from 'antd';
import PropTypes from 'prop-types';
import './img-upload.css'

export default class ImgUpload extends React.Component {
  /*
    组件属性
    id:组件动态标识,表明组件是否需要修改的唯一标识
    imgTitle:组件的中文描述
    height:图片外框的高度
    imgFile:图片文件
    renderState:图片初始化状态,//init:初始化,loading:正在上传,upload:上传成功
    imgSrc:图片src路径
    isPreview: false//是否显示弹出层预览全图
    titleClass:"" //文本描述信息的样式
    getImgFile:function():获取图片文件信息
  */
  constructor(props) {
    super(props)
    this.state = {
      imgFile: null,
      imgSrc: this.props.imgSrc||"",
      renderState: this.props.renderState||"init",
      isPreview: false,
      disabled:this.props.disabled || false
    }
  }

  static defaultProps = {
    imgTitle: "",
    height: "200px",
    renderState: "init",
    imgSrc: "",
    titleClass: "",
    accept:"*"
  }

  static propTypes = {
    imgTitle: PropTypes.string,
    renderState: PropTypes.oneOf(['init', 'loading', 'upload']),
    imgSrc: PropTypes.string,
    titleClass: PropTypes.string,
    accept:PropTypes.string
  };

  componentWillReceiveProps(nextProps){
    if(this.props.imgSrc != nextProps.imgSrc){
      this.setState({imgSrc:nextProps.imgSrc})
    }
    if(this.props.renderState != nextProps.renderState){
      this.setState({renderState:nextProps.renderState})
    }
    if(this.props.disabled != nextProps.disabled){
      this.setState({disabled:nextProps.disabled})
    }  

  }

  renderInit() {//初始化渲染
    return (
      <div className="img-box" style={{ height: this.props.height }}>
        <input type="file" className="img-file" onChange={this.imgChange.bind(this)} accept={this.props.accept} />
        <div className={"img-add " + this.props.titleClass}>
          <Icon type="plus" className="img-add-icon" />
          <div>{this.props.imgTitle}</div>
        </div>
      </div>
    )
  }

  renderLoading() {//正在上传
    return (
      <div className="img-box" style={{ height: this.props.height }}>
        <img src="/static/admin/img/loading.gif" className="img-loading" />
      </div>
    )
  }

  renderUpload() {//上传完成
    const imgSrc = (this.state.imgSrc&&this.state.imgSrc!="")?this.state.imgSrc:"/static/admin/img/error_img.jpg"
    const imgBox = this.state.disabled ? "img-box-preview-hide" : "img-box-preview-show"
    return (
      <div className={imgBox} style={{ height: this.props.height }}>
        <img src={imgSrc} className="img-wh" />
        <div className="img-preview">
          <Icon type="eye-o" className="img-operate" onClick={this.original.bind(this)} />
          <Icon type="delete" className="img-operate" onClick={this.deleteImg.bind(this)} />
        </div>
      </div>
    )
  }

  renderImg() {
    if (this.state.renderState === "init") {
      return this.renderInit()
    } else if (this.state.renderState === "loading") {
      return this.renderLoading()
    } else if (this.state.renderState === "upload") {
      return this.renderUpload()
    }
  }

  imgChange(event) {//获取文件图片
    this.setState({ imgFile: event.target.files[0], renderState: "loading" }, () => {
      this.previewImg()
    })
  }

  previewImg() {//本地预览
    const that = this;
    const file = this.state.imgFile;
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function (e) {
      that.setState({ renderState: "upload", imgSrc: this.result })
    }
  }

  original() {//原图查看
    this.setState({ isPreview: true })
  }

  deleteImg() {//删除图片
    this.setState({ renderState: "init", imgFile: null, isPreview: false, imgSrc: "" })
  }

  resetImgSrc(){
    this.setState({ renderState: this.props.renderState, imgFile: null, imgSrc: this.props.imgSrc })
  }

  getImgFile() {
      return {file:this.state.imgFile,src:this.state.imgSrc}
  }

  cancelModal() {//关闭弹窗
    this.setState({ isPreview: false })
  }

  render() {
    return (
      <div>
        {this.renderImg()}
        <Modal visible={this.state.isPreview} footer={null}
          onCancel={this.cancelModal.bind(this)}
          width="auto" wrapClassName="img-center"
          style={{ display: "inline-block" }}
        >
          <img src={this.state.imgSrc} className="preview-all" />
        </Modal>
      </div>
    )
  }
}

组件css文件(img-upload.css)

.img-box{
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  margin-left:30px;
  margin-right:30px;
}

.img-box-preview-show{
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  margin-left:30px;
  margin-right:30px;
}
.img-box-preview-hide{
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  margin-left:30px;
  margin-right:30px;
}
.img-file{
    position: absolute;
    top: 50%;
    left: 50%;
    width: 36px;
    height: 36px;
    z-index: 9999;
    margin-left: -18px;
    margin-top: -41px;
    opacity: 0;
    filter:Alpha(opacity=0);
}
.img-add {
    width: 130px;
    text-align: center;
    position: absolute;
    top: 50%;
    margin-top: -32px;
    left: 50%;
    margin-left: -65px;
}
.img-add-icon{
  font-size: 24px;
  font-weight: bold;
}
.img-preview{
  display: none;
  position: absolute;
  top:50%;
  left:50%;
  margin-top:-22px;
  margin-left:-44px;
}
.img-box-preview-show:hover .img-preview{
   display:block;
}
.img-operate{
  font-size:24px;
  margin:10px;
  color: red;
}
.img-loading{
  position: absolute;
  top:50%;
  left:50%;
  margin-top:-50px;
  margin-left:-50px;
}
.preview-all {
  width:100%;
}
.img-center{
  text-align: center;
}
.img-wh{
  width:100%;
  height:100%;
} 

使用方法

 <ImgUpload 
     imgTitle="国家首页配图(1920*470)" 
     height="320px" 
     id={this.props.countryInfo._id}
     imgSrc={this.props.countryInfo.bannerPath} 
     ref="bannerPath"
     renderState={this.props.countryState == "add" ? "init" : "upload"} />

我们可以根据ref获取到该组件,然后调用组件的方法获取图片文件,之后文件的保存就是你按部就班的插入数据库就行了。例如: const bannnerFile = this.refs.bannerPath.getImgFile();

效果图

初始化

这里写图片描述

添加图片后
这里写图片描述

预览原图
这里写图片描述

猜你喜欢

转载自blog.csdn.net/mafan121/article/details/76661527