自定义input上传图片组件

2019/12/03 15:20
阅读数 51

自定义input上传图片组件,美化样式

前段时间因为项目需求,做过一个上传图片组件,这里分享下大致思路,希望对有需要的童鞋有所帮助~~~


功能需求:1.上传图片限制大小、分辨率、类型
         2.上传图片支持自由裁剪
         3.图片上传后支持预览和删除

效果图,只截取了一小部分,大致看下就ok啦,是不是感觉比原生的好看多了^_^
图片描述

项目是基于react框架写的,话不多说,开始撸代码~~~

Step1:编写基础html结构

<div>
    <input
      type="file"
      accept="image/jpeg, image/gif, image/png, image/bmp"
      styleName="input-file"
    />
    <label htmlFor="file" styleName="ant-upload">  
        {uploadButton}
    </label>
</div>

// uploadButton组件代码如下: 
const uploadButton = (
      <div styleName="upload-plus-text">
        <Icon type="plus" />
        <div className="ant-upload-text">上传照片</div>
      </div>
    );

Step2:基础样式

input-file {
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  z-index: -1;
}

.ant-upload {
  @w: 100px;

  width: @w;
  height: @w;
  padding: 5px;
  background-color: #fafafa;
  border: 1px dashed #d9d9d9;
  border-radius: 4px;
  display: block;
  cursor: pointer;
  position: relative;
}

.upload-plus-text {
  width: 100%;
  text-align: center;
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);

  i {
    font-size: 28px;
    color: #999;
  }

  .ant-upload-text {
    margin-top: 8px;
    font-size: 12px;
    color: #666;
  }
}

Step3:添加事件处理

对上传图片的类型、大小和分辨率进行检测

<input
  type="file"
  id='file'
  accept="image/jpeg, image/gif, image/png, image/bmp"
  styleName="input-file"
  onChange={e => {
    this.onFileChange(e);
  }}
/>
<label htmlFor="file" styleName="ant-upload">
  {uploadButton}
</label>
</div>

// 一些常量定义
const IMAGE_MIN_WIDTH = 1280; // 上传图片最小宽
const IMAGE_MIN_HEIGHT = 800; // 上传图片最小高
const IMAGE_MAX_SIZE = 1024 * 1024; // 上传图片最大大小

// 处理上传文件
  onFileChange(e) {
    const file = e.target.files[0];
    e.target.value = ''; // 再次上传同一文件进行裁剪
    if (this.handleBeforeUpload(file)) {
      const reader = new FileReader();
      reader.onload = e => {
        const src = e.target.result;
        const image = new Image();
        const _this = this;
        image.onload = () => {
          const width = image.width;
          const height = image.height;
          if (width >= IMAGE_MIN_WIDTH && height >= IMAGE_MIN_HEIGHT) {
            _this.setState({
              initialImageUrl: src,
              showCropModal: true
            });
          } else {
            message.error('照片分辨率小于1280*800');
          }
        };
        image.src = src;
      };
      reader.readAsDataURL(file);
    }
  }

// 检查照片格式、大小等信息
  handleBeforeUpload(file) {
    if (file) {
      const sizeOk = file.size < IMAGE_MAX_SIZE;
      const typeReg = new RegExp(/^image\/bmp|gif|jpg|jpeg|png$/, 'i');
      const typeOk = typeReg.test(file.type);

      if (!typeOk) {
        message.error('照片格式有误');
      } else if (!sizeOk) {
        message.error('照片大小超过1M');
      }

      return sizeOk && typeOk;
    }
  }

Step4:裁剪功能

代码较多就不展示了= =,使用的是react-cropper

Step5:预览和删除功能

预览功能实现思路就是通过判断是否已经上传图片来展示不同的状态。未上传展示uploadButton组件,已上传就展示imagePreview组件。
通过判断是否已经上传图片来控制input标签的id属性值,未上传图id='file',已上传图片将id='',这样一来,再次去点击label的时候由于for属性找不到对应的id,就不会触发input上onChange事件

<div>
    <input
      type="file"
      id={imageUrl ? '' : 'file'}
      accept="image/jpeg, image/gif, image/png, image/bmp"
      styleName="input-file"
      onChange={e => {
        this.onFileChange(e);
      }}
    />
    <label htmlFor="file" styleName="ant-upload">
      {imageUrl ? imagePreview : uploadButton}
    </label>
</div>
<Modal
  visible={showPreviewModal}
  title="图片预览"
  footer={null}
  width={700}
  onCancel={this.handlePreviewCancel}>
  <img alt="" style={{ width: '100%' }} src={imageUrl} />
</Modal>
// imagePreview组件代码如下
const imagePreview = (
  <div
    styleName="image-background-preview"
    style={{ backgroundImage: `url(${imageUrl})` }}>
    <div styleName="preview-image">
      <span styleName="preview-image-btn">
        <a title="预览图片" href="javascript:;">
          <Icon
            type="eye"
            styleName="icon-btn"
            onClick={this.handlePreview}
          />
        </a>
        <a title="删除图片" href="javascript:;">
          <Icon
            type="delete"
            styleName="icon-btn"
            onClick={this.swapImageFile}
          />
        </a>
      </span>
    </div>
  </div>
);
   
// 预览图片
handlePreview() {
  this.setState({
    showPreviewModal: true
  });
}

// 删除图片
swapImageFile() {
  this.setState({ imageUrl: '' });
}

写在最后:项目涉及代码较多,文章只展示了大部分代码,一些具体细节代码可能就没有展示了,还望见谅,第一次写文章,可能比较混乱,有问题还望大家指出~~~ ^_^

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部