• 技术文章 >web前端 >前端问答

    react怎么实现图片选择

    藏色散人藏色散人2023-01-19 14:21:40原创48

    react实现图片选择的方法:1、使用import引入“react-native-image-picker”插件;2、使用“{this.setState({uploadImgs: urls})}}src={uploadImgs}/>”调用实现图片选择上传即可。

    本教程操作环境:Windows10系统、react18.0.0版、Dell G3电脑。

    react怎么实现图片选择?

    React Native七牛上传+本地图片选择

    参考:

    react-native-image-crop-picker图片选择并裁减 //这个看需求使用
    https://github.com/ivpusic/react-native-image-crop-picker
    react-native-image-picker图片选择
    https://github.com/react-native-image-picker/react-native-image-picker
    react-native-qiniu
    https://github.com/buhe/react-native-qiniu

    我只要一个多图片上传功能,所以就写简单一点

    效果

    272c9e4e9370c56b75329fa12000ebf.jpg

    已上传状态

    8a71bfdf34877db7133cf01a8362a08.jpg

    上传中状态

    步骤

    1、手机图片、视频选择功能

    用react-native-image-picker插件

    yarn add react-native-image-picker;ios需要pod install;

    import {launchCamera, launchImageLibrary, ImageLibraryOptions, PhotoQuality} from 'react-native-image-picker';
    /**
     * 从相册选择图片;
     * sourceType: 'camera'  打开相机拍摄图片
    **/
    export async function chooseImage(options: {
      count?: number,
      quality?: PhotoQuality
      sourceType?: 'camera',  //默认'album'
    } = {}) {
      return new Promise<any>(async(resolve, reject) => {
        const Opts: ImageLibraryOptions = {
          mediaType: 'photo',
          quality: options.quality || 1,
          selectionLimit: options.count || 1
        };
        const result = options.sourceType == 'camera'? 
          await launchCamera(Opts) : 
          await launchImageLibrary(Opts);
        resolve(result)
      })
    }
    /**
     * 从相册选择视频;
     * sourceType: 'camera'  打开相机拍摄视频
    **/
    export async function chooseVideo(options: {
      count?: number,
      quality?: 'low' | 'high'
      sourceType?: 'camera',  //默认'album'
    } = {}) {
      return new Promise<any>(async(resolve, reject) => {
        const Opts: ImageLibraryOptions = {
          mediaType: 'video',
          videoQuality: options.quality,
          selectionLimit: options.count || 1
        };
        const result = options.sourceType == 'camera'? 
          await launchCamera(Opts) : 
          await launchImageLibrary(Opts);
        resolve(result)
      })
    }

    2、七牛上传文件功能

    class qiniuUpload {
      private UP_HOST = 'http://upload.qiniu.com';
      // private RS_HOST = 'http://rs.qbox.me';
      // private RSF_HOST = 'http://rsf.qbox.me';
      // private API_HOST = 'http://api.qiniu.com';
      public upload = async(uri:string, key:string, token:string) => {
        return new Promise<any>((resolve, reject) => {
          let formData = new FormData();
          formData.append('file', {uri: uri, type: 'application/octet-stream', name: key});
          formData.append('key', key);
          formData.append('token', token);
        
          let options:any = {
            body: formData,
            method: 'post',
          };
          fetch(this.UP_HOST, options).then((response) => {
            resolve(response)
          }).catch(error => {
            console.error(error)
            resolve(null)
          });  
        })
      }
       //...后面再加别的功能
    }
    const qiniu = new qiniuUpload();
    export default qiniu;
    import qiniu from '@/modules/qiniu/index'
    ...
      /**
       * 上传视频图片
       */
      uploadFile: async (filePath: string) => {
        const res = await createBaseClient('GET', '/v1/file')();  //这是接口请求方法,用来拿后端的七牛token、key
        
        if( !res ) {
          return res;
        }
        const { key, token } = res;
        const fileSegments = filePath.split('.');
        const fileKey = key + '.' + fileSegments[fileSegments.length - 1];
        try {
          const result = await qiniu.upload(filePath, fileKey, token)
          if(result && result.ok) {
            return {
              url: ASSET_HOST + '/' + fileKey,  //ASSET_HOST是资源服务器域名前缀
            };
          }else {
            return null
          }
        } catch (error) {
          return null;
        }
      },
    ...

    3、多图上传组件封装

    (这里Base、Image、ActionSheet都是封装过的,需看情况调整)

    import React from 'react'
    import {
      ViewStyle,
      StyleProp,
      ImageURISource,
      ActivityIndicator
    } from 'react-native'
    import Base from '@/components/Base';
    import { Image, View, Text } from '@/components';   //Image封装过的,所以有些属性不一样
    import ActionSheet from "@/components/Feedback/ActionSheet";  //自己封装
    import styles from './styleCss';  //样式就不放上来了
    interface Props {
      type?: 'video'
      src?: string[]
      count?: number
      btnPath?: ImageURISource
      style?: StyleProp<ViewStyle>
      itemStyle?: StyleProp<ViewStyle>
      itemWidth?: number
      itemHeight?: number  //默认正方形
      onChange?: (e) => void
    }
    interface State {
      imageUploading: boolean
      images: string[]
    }
    /**
     * 多图上传组件
     * * type?: 'video'
     * * src?: string[]   //图片数据,可用于初始数据
     * * count?: number    //数量
     * * btnPath?: ImageURISource   //占位图
     * * itemStyle?: item样式,width, height单独设
     * * itemWidth?: number
     * * itemHeight?: number  //默认正方形
     * * onChange?: (e:string[]) => void
    **/
    export default class Uploader extends Base<Props, State> {
      public state: State = {
        imageUploading: false,
        images: []
      };
      public didMount() {
        this.initSrc(this.props.src)
      }
      public componentWillReceiveProps(nextProps){
        if(nextProps.hasOwnProperty('src') && !!nextProps.src){
          this.initSrc(nextProps.src)
        }
      }
      /**
       *初始化以及改动图片
      **/
      private initSrc = (srcProp:any) => {
        if(!this.isEqual(srcProp, this.state.images)) {
          this.setState({
            images: srcProp
          })
        }
      }
      
      public render() {
        const { style, btnPath, count, itemStyle, itemWidth, itemHeight, type } = this.props;
        const { imageUploading, images } = this.state;
        let countNumber = count? count: 1
        return (
          <React.Fragment>
            <View style={[styles.uploaderBox, style]}>
              {images.length > 0 && images.map((res, ind) => (
                <View style={[styles.item, itemStyle]} key={res}>
                  <View style={styles.imgItem}>
                    <Image
                      source={{uri: res}}
                      width={this.itemW}
                      height={this.itemH}
                      onPress={() => {
                        this.singleEditInd = ind;
                        this.handleShowActionSheet()
                      }}
                    />
                    <Text style={styles.del} onPress={this.handleDelete.bind(null, ind)}>删除</Text>
                  </View>
                </View>
              ))}
              {images.length < countNumber  &&
                <View style={[styles.item, itemStyle]}> 
                  {imageUploading? (
                    <View style={[{
                      width: this.itemW,
                      height: this.itemH,
                    }, styles.loading]}>
                      <ActivityIndicator size={this.itemW*0.4}></Loading>
                      <Text style={{
                        fontSize: 14,
                        color: '#888',
                        marginTop: 5
                      }}>
                        上传中...
                      </Text>
                    </View>
                  ): (
                    <View style={styles.btn}>
                      <Image
                        source={btnPath || this.assets.uploadIcon}
                        width={this.itemW}
                        height={this.itemH}
                        onPress={() => {
                          this.singleEditInd = undefined;
                          this.handleShowActionSheet()
                        }}
                      />
                    </View>
                  )}
                  
                </View>
              }
              
            </View>
            <ActionSheet
              name="uploaderActionSheet"
              options={[{
                name: type == 'video'? '拍摄': '拍照',
                onClick: () => {
                  if(type == 'video') {
                    this.handleChooseVideo('camera')
                  }else if(this.singleEditInd !== undefined) {
                    this.handleChooseSingle('camera')
                  }else {
                    this.handleChooseImage('camera')
                  }
                }
              }, {
                name: '相册',
                onClick: () => {
                  if(type == 'video') {
                    this.handleChooseVideo()
                  }else if(this.singleEditInd !== undefined) {
                    this.handleChooseSingle()
                  }else {
                    this.handleChooseImage()
                  }
                }
              }]}
            ></ActionSheet>
          </React.Fragment>
        );
      }
      private get itemW() {
        return this.props.itemWidth || 92
      }
      private get itemH() {
        return this.props.itemHeight || this.itemW;
      }
      
      private isEqual = (firstValue, secondValue) => {
        /** 判断两个值(数组)是否相等 **/
        if (Array.isArray(firstValue)) {
          if (!Array.isArray(secondValue)) {
            return false;
          }
          if(firstValue.length != secondValue.length) {
            return false;
          }
          return firstValue.every((item, index) => {
            return item === secondValue[index];
          });
        }
        return firstValue === secondValue;
      }
      private handleShowActionSheet = () => {
        this.feedback.showFeedback('uploaderActionSheet');  //这是显示ActionSheet选择弹窗。。。
      }
      private handleChooseImage = async (sourceType?: 'camera') => {
        const { imageUploading, images } = this.state;
        const { count } = this.props
        if (imageUploading) {
          return;
        }
        let countNumber = count? count: 1
        const { assets } = await this.interface.chooseImage({  //上面封装的选择图片方法
          count: countNumber,
          sourceType: sourceType || undefined,
        });
        
        if(!assets) {
          return;
        }
        this.setState({
          imageUploading: true,
        });
        
        let request:any = []
        assets.map(res => {
          let req = this.apiClient.uploadFile(res.uri)   //上面封装的七牛上传方法
          request.push(req)
        })
        Promise.all(request).then(res => {
          let imgs:any = []
          res.map((e:any) => {
            if(e && e.url){
              imgs.push(e.url)
            }
          })
          imgs = [...images, ...imgs];
          this.setState({
            images: imgs.splice(0,countNumber),
            imageUploading: false,
          },
            this.handleChange
          );
        })
        
      }
      private singleEditInd?: number;  //修改单个时的索引值
      private handleChooseSingle = async(sourceType?: 'camera') => {
        let { imageUploading, images } = this.state;
        if (imageUploading) {
          return;
        }
        
        const { assets } = await this.interface.chooseImage({   //上面封装的选择图片方法
          count: 1,
          sourceType: sourceType || undefined,
        });
        if(!assets) {
          return;
        }
        this.setState({
          imageUploading: true,
        });
        const res = await this.apiClient.uploadFile(assets[0].uri)   //上面封装的七牛上传方法
        if(res && res.url && this.singleEditInd){
          images[this.singleEditInd] = res.url
        }
        this.setState({
          images: [...images],
          imageUploading: false,
        },
          this.handleChange
        );
        
      }
      private handleChooseVideo = async(sourceType?: 'camera') => {
        const { onChange } = this.props
        let { imageUploading } = this.state;
        if (imageUploading) {
          return;
        }
        
        const { assets } = await this.interface.chooseVideo({
          sourceType: sourceType
        });
        if(!assets) {
          return;
        }
        this.setState({
          imageUploading: true,
        });
        const res = await this.apiClient.uploadFile(assets[0].uri)   //上面封装的七牛上传方法
        if(res && res.url){
          //视频就不在组件中展示了,父组件处理
          if(onChange) {
            onChange(res.url)
          }
        }
        this.setState({
          imageUploading: false,
        });
        
      }
      private handleDelete = (ind:number) => {
        let { images } = this.state
        images.splice(ind,1)
        this.setState({
          images: [...images]
        },
          this.handleChange
        )
      }
      private handleChange = () => {
        const { onChange } = this.props
        const { images } = this.state
        if(onChange) {
          onChange(images)
        }
      }
    }

    4、最后调用

    import Uploader from "@/components/Uploader";
    ...
              <Uploader
                count={6}
                onChange={urls => {
                  this.setState({
                    uploadImgs: urls
                  })
                }}
                src={uploadImgs}
              />
    ...

    推荐学习:《react视频教程

    以上就是react怎么实现图片选择的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:React
    上一篇:react安装依赖命令有哪些 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • react应用打包部署到tomcat怎么做• react中怎么禁止button渲染• react组件mount好几次怎么办• react安装依赖命令有哪些
    1/1

    PHP中文网