react-native 底部彈窗選項卡 + 上傳圖片 +預覽圖片

效果圖,
支持默認圖片,上傳中的狀態,最大上傳數量,預覽大圖等功能
在這裏插入圖片描述在這裏插入圖片描述

import React, { Component } from "react";
import {
  StyleSheet,
  View,
  Text,
  Image,
  TouchableOpacity,
  Modal,
  Platform
} from "react-native";
import { scaleSizeW, setSpText, uploadImag } from "../utils/util";
import ToastBox from "../utils/Toast";
import ActionSheet from "react-native-actionsheet";
import Toast from "../utils/Toast";
import config from "../utils/config";
import ImageViewer from "react-native-image-zoom-viewer";

/*
 * maxNum  (number)上傳的最大數量
 * onChange (fun) 返回文件列表arrary
 * actionText  + 下面的文字
 * noRequire  選傳
 * initList 已有的圖片數組
 */
export default class ImgUpLoad extends Component {
  constructor(props) {
    super(props);
    this.state = {
      flieLists: [],
      visible: false,
      upLoadState: 2 //1上傳中 2上傳完成
    };
  }
  componentWillMount() {
    const { initList, size } = this.props;
    console.log(initList);
    let flieLists = initList ? initList : [];
    this.setState({
      flieLists
    });
  }
  feedBack = () => {
    // this.props.onChange && this.props.onChange(this.state.flieLists);
    if (this.props.onChange) {
      let arr = [...this.state.flieLists];
      // console.log("feedBack: ",arr)
      this.props.onChange(arr);
    }
  };
  // 打開相冊
  selectFromAblum(type) {
    const { userInfo, setUserInfo } = this.props;
    uploadImag(type, image => {
      // const param = `data:${image.mime};base64,${image.data}`;
      console.log(image);
      let maxSize = image.size / 1024 / 1024, // MB
        minSize = image.size / 1024; // KB
      if (maxSize > 1) {
        ToastBox.showTop("圖片大小不符合要求,請重新選擇");
        return;
      }
      // ToastBox.showTop(`${image.size}`)
      if(Platform.OS=='android'){
        let DateName = new Date().getTime();
        image.filename = DateName + ".jpg";
      }
      
      let file = {
        uri: image.path,
        type: "multipart/form-data",
        name: image.filename
      };
      let formData = new FormData();
      formData.append("file", file);
      this.setState({
        upLoadState: 1
      });
      fetch(config.uploadImg, {
        method: "post",
        body: formData,
        headers: {
          "Content-Type": "multipart/form-data;charset=utf-8"
        }
        // body: JSON.stringify({
        //   base64Str:param
        // }),
      })
        .then(res => {
          console.log(res);
          // console.log(res.text())
          return res.json();
        })
        .then(response => {
          console.log(response);
          if (response.code == 0) {
            this.setState({
              upLoadState: 2
            });
            console.log(response.data.uri);
            let myfile = response.data.uri;
            let flieLists = [...this.state.flieLists];
            flieLists.push(myfile);
            this.setState({ flieLists }, () => {
              this.feedBack();
            });
          }
        })
        .catch(err => {
          console.log(err);
          ToastBox.showTop("圖片上傳失敗,請重試");
          this.setState({
            upLoadState: 2
          });
        });
    });
  }

  takePhoto(type) {
    const { userInfo, setUserInfo } = this.props;
    uploadImag(type, image => {
      // const param = `data:${image.mime};base64,${image.data}`;
      // console.log(param)
      console.log(image);
      let maxSize = image.size / 1024 / 1024, // MB
        minSize = image.size / 1024; // KB
      let filename;
      if (maxSize > 1) {
        ToastBox.showTop("圖片大小不符合要求,請重試");
        return;
      }
      // ToastBox.showTop(`${image.size}`)
      let DateName = new Date().getTime();
      filename = DateName + ".jpg";
      let file = {
        uri: image.path,
        type: "multipart/form-data",
        name: filename
      };
      this.setState({
        upLoadState: 1
      });
      let formData = new FormData();
      formData.append("file", file);

      fetch(config.uploadImg, {
        method: "post",
        body: formData,
        headers: {
          "Content-Type": "multipart/form-data;charset=utf-8"
        }
        // body: JSON.stringify({
        //   base64Str:param
        // }),
      })
        .then(res => res.json())
        .then(response => {
          if (response.code == 0) {
            // ToastBox.showTop(`圖片上傳成功:${JSON.stringify( response)}`)
            let myfile = response.data.uri;
            let flieLists = [...this.state.flieLists];
            flieLists.push(myfile);
            this.setState({ flieLists, upLoadState: 2 }, () => {
              this.feedBack();
            });
          }
        })
        .catch(err => {
          console.log(err);
          ToastBox.showTop("圖片上傳失敗,請重試");
          this.setState({upLoadState: 2})
        });
    });
  }
  // 開打底部選項卡
  showActionSheet = () => {
    if (this.props.maxNum && this.state.flieLists.length >= this.props.maxNum) {
      Toast.show("上傳數量達到極限");
      return;
    }
    this.ActionSheet.show();
  };
  // 刪除圖片
  delImg = index => {
    let flieLists = [...this.state.flieLists];
    flieLists.splice(index, 1);
    console.log(flieLists);
    this.setState({ flieLists: flieLists }, () => {
      this.feedBack();
    });
  };
  render() {
    const { flieLists, visible, upLoadState } = this.state;
    const { maxNum, actionText, size, noRequire, initList } = this.props;
    if (size) {
      let num = scaleSizeW(size);
      console.log(num)
      styles.upLoadItem = { ...styles.upLoadItem, width: num, height: num };
      styles.image = { ...styles.image, width: num, height: num };
    }
    console.log(flieLists);
    return (
      <View style={styles.upLoad}>
        {flieLists.length > 0 &&
          flieLists.map((item, index) => {
            console.log(item);
            const images = [
              {
                // Simplest usage.
                url: item
              }
            ];
            return (
              <TouchableOpacity
                onPress={() => {
                  this.setState({ visible: true });
                }}
                key={index}
                style={styles.upLoadItem}
              >
                <Image source={{ uri: item }} style={styles.image} />
                <Modal
                  style={{ width: "100%", height: "100%" }}
                  visible={visible}
                  transparent
                >
                  <ImageViewer
                    backgroundColor={"rgba(0,0,0,0.8)"}
                    onClick={() => {
                      this.setState({ visible: false });
                    }}
                    imageUrls={images}
                  />
                </Modal>
                <Text
                  style={styles.close}
                  onPress={() => {
                    this.delImg(index);
                  }}
                >
                  {"\ue613"}
                </Text>
              </TouchableOpacity>
            );
          })}
        {/* 超過最大數隱藏上傳 */}
        {maxNum > flieLists.length && (
          <TouchableOpacity
            activeOpacity={1}
            onPress={() => {
              this.showActionSheet();
            }}
          >
            {upLoadState == 2 && (
              <View style={[styles.upLoadItem, styles.addBtn]}>
                <Text style={styles.add}>{"\ue612"}</Text>
                <Text style={styles.addText}>
                  {actionText ? actionText : "上傳"}
                </Text>
                {noRequire && <Text style={styles.otherText}>(選傳)</Text>}
              </View>
            )}
            {upLoadState == 1 && (
              <View style={[styles.upLoadItem, styles.loadingImgWrap]}>
                <Image
                  style={styles.loadingImg}
                  source={require("../assets/image/timg.gif")}
                ></Image>
              </View>
            )}
          </TouchableOpacity>
        )}
        <ActionSheet
          ref={o => (this.ActionSheet = o)}
          options={["拍照", "從相冊上傳", "取消"]}
          cancelButtonIndex={2}
          destructiveButtonIndex={1}
          onPress={index => {
            if (index === 0) {
              this.takePhoto(1);
            } else if (index === 1) {
              this.selectFromAblum(2);
            }
          }}
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  upLoad: {
    // width: "100%",
    flexDirection: "row",
    flexWrap: "wrap",
    // paddingLeft: scaleSizeW(20),
    paddingTop: scaleSizeW(20)
    // justifyContent: "flex-start"
  },
  upLoadItem: {
    width: scaleSizeW(204),
    height: scaleSizeW(204),
    borderRadius: scaleSizeW(8),
    borderColor: "#ccc",
    borderWidth: StyleSheet.hairlineWidth,
    justifyContent: "center",
    alignItems: "center",
    marginRight: scaleSizeW(20),
    marginBottom: scaleSizeW(20),
    position: "relative"
  },
  loadingImgWrap: {
    backgroundColor: "#fff"
  },
  loadingImg: {
    width: scaleSizeW(100),
    height: scaleSizeW(100),
    borderRadius: scaleSizeW(8)
  },
  addBtn: {
    borderStyle: "dashed",
    backgroundColor: "rgba(247,250,253,1)"
  },
  image: {
    width: scaleSizeW(204),
    height: scaleSizeW(204),
    borderRadius: scaleSizeW(8)
  },
  add: {
    fontFamily: "iconfont",
    fontSize: setSpText(40),
    color: "#8595A6"
  },
  addText: {
    color: "#FF6737",
    fontSize: setSpText(24),
    textAlign: "center"
  },
  otherText: {
    fontSize: scaleSizeW(24),
    color: "rgba(76,154,255,0.6)",
    marginTop: scaleSizeW(8),
    position: "absolute",
    bottom: scaleSizeW(30),
    left: "50%",
    marginLeft: scaleSizeW(-30)
  },
  close: {
    position: "absolute",
    right: scaleSizeW(12),
    zIndex: 10,
    top: scaleSizeW(12),
    fontSize: setSpText(50),
    fontFamily: "iconfont",
    color: "#999"
  }
});

上傳圖片,拍照組件

import ImagePicker from 'react-native-image-crop-picker';
/**
 * 上傳圖片
 * @param callback 上傳成功後的回調函數
 */
export function uploadImag(type,callback) {
  if(type==1){
    ImagePicker.openCamera({
      cropping: false,
      compressImageQuality: 0.3,
      includeExif: true
    }).then((image) => {
      callback(image)
    }).catch(err=>{console.log(err)})
  }else if(type==2){
    ImagePicker.openPicker({
      cropping: false,
      compressImageQuality: 0.5,
      includeExif: true
    }).then((image) => {
      callback(image)
    }).catch(err=>{console.log(err)});
  }
}

export function uploadFile(callback) {
  DocumentPicker.show(
    {
      filetype: [DocumentPickerUtil.allFiles()]
    },
    (error, res) => {
      if (error) {
        Toast.message('上傳文件失敗');
      } else {
        let source = {
          uri: res.uri,
          type: 'multipart/form-data',
          name: res.fileName
        };
        let params = {
          image: source,
          imageFileName: 'images'
        };
        Api.uploadFile(params).then(res => {
          if (res.success) {
            if (typeof callback === 'function') {
              callback(res);
            }
          } else {
            Toast.message('上傳圖片失敗');
          }
        });
      }
    }
  );
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章