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

属性名说明类型默认值可选值
imgTitle组件的中文描述String“”
height图片外框的高度String200px
renderState图片初始化状态Stringinitinit,loading,upload
imgSrc图片src路径String“”
titleClass文本描述信息的样式String“”
disabled是否禁用组件Booleanfalsetrue或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();

效果图

初始化

这里写图片描述

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

预览原图
这里写图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐