react native 实现本地相册、拍照、显示上传的图片、上传图片文件(react-native-image-picker)

目录:

  1. 思路
  2. 安装中间件
  3. 获取用户相册/相机权限,以及主要步骤
  4. 调用接口,实现上传图片文件

思路

  • 获取用户相册/相机权限;
  • 实现本地相册选择/相机拍摄;
  • 封装上传接口,将照片上传到服务器;
  • 将选择的照片,展示出来(注意点:展示时,需要使用本地路径,而不是服务器地址);

具体步骤

1. 安装中间件 react-native-image-picker

版本:

"react": "16.8.3",
"react-native": "0.59.9",
"react-native-image-picker": "0.27.0"

2. 获取用户相册/相机权限,以及主要步骤

  • 设置选择照片的弹窗样式
  • 调用 ImagePicker.showImagePicker 函数选择本地相册/拍照
  • 设置获取相机权限提示
  • 区分 IOS / Android 上传的文件是否加前缀 file//
  • 调用上传接口 uploadEquipImg
【主要代码如下】

...
import ImagePicker from 'react-native-image-picker';
import {
    uploadEquipImg
} from '../../action/TestAction'; // 上传图片接口文件,此函数在下一步详细描述
...


class Test extends Component {
    constructor(props) {
        super(props);
        this.state = {
            ...
            localPhoOption: [] // 存储本地文件路径,用户本地展示图片
            ...
        }
    }
    
    
    // 添加图片 点击
    handleAddPicCheck() {
        // console.warn('添加图片------check')
        let { localPhoOption } = this.state
        let { props } = this
        let that = this
        const options = {
            title: '选择图片',
            cancelButtonTitle: '取消',
            takePhotoButtonTitle: '拍照',
            chooseFromLibraryButtonTitle: '相册',
            cameraType: 'back',
            mediaType: 'photo',
            videoQuality: 'high',
            durationLimit: 10,
            maxWidth: 720,
            maxHeight: 1280,
            aspectX: 2,
            aspectY: 1,
            quality: 1,
            angle: 0,
            allowsEditing: false,
            noData: false,
            storageOptions: {
                skipBackup: true,
                path: 'PickLocalImg' // 存储本地地址
            }
        };

        ImagePicker.showImagePicker(options, async (res) => {
            if (res.didCancel) {
                console.log('User cancelled photo picker');
            }
            else if (res.error) {
                // 用户选择不授权时,提醒以下信息
                console.log('ImagePicker Error: ', res.error);
                if(res.error.indexOf('Camera permissions not granted') > -1){
                    Alert.alert(('提示信息', 'APP需要使用相机,请打开相机权限允许APP使用'), [{
                        text: '设置',
                        onPress: () => {
                            Linking.openURL('app-settings:')
                                .catch(err => console.log('error', err))
                        }
                    },{
                        text: '取消'
                    }])
                }
                if(res.error.indexOf('Photo library permissions not granted') > -1){
                    Alert.alert('提示信息', 'APP需要使用相册,请打开相册权限允许APP使用', [{
                        text: '设置',
                        onPress: () => {
                            Linking.openURL('app-settings:')
                                .catch(err => console.log('error', err))
                        }
                    },{
                        text: '取消'
                    }]);
                }
            }
            else if (res.customButton) {
                console.log('User tapped custom button: ', res.customButton);
            } else {
                // 用户授权并选择照片/拍照后,调用接口
                let source;  //保存选中的图片
                if (Platform.OS === 'android') {
                    source = res.uri;
                } else {
                    source = res.uri.replace('file://','');
                }
                const formData  = new FormData();
                // 文件类型根据对应的后端接口改变!!!
                let file = { uri: source, type: 'multipart/form-data', name: res.fileName };
                formData.append('file',file);
                let params = {
                    formData
                }
                //上传图片接口
                let imgResult = await uploadEquipImg(params);
                if(imgResult.error_code == 0) {
                    // 提交订单
                    show('上传成功');
                    let {url} = imgResult.data

                    localPhoOption.push(source); // 存储本地图片地址,方便在APP中本地查看展示,注意⚠️不是后端返回的图片地址
                    that.setState({ 
                        localPhoOption
                     });
                } else {
                    let error_msg = imgResult.error_msg || imgResult.message
                    show(error_msg);
                }
            }
        })


    }
    
    ...
    render() {
        let { state } = this
        return (
            <View>
                <Text>添加图片</Text>
                <View style={list_common_item.addpic_cont}>
                    {/* 显示上传后的照片 */}
                    {
                        state.localPhoOption.length
                            ? state.localPhoOption.map((item, index) => this.renderPicItem(item, index) )
                            : null
                    }
                    <TouchableOpacity
                        activeOpacity={.8}
                        onPress={() => this.handleAddPicCheck()}
                        >
                        {/* 点击此图,调用上传图片,一般此图是个➕号 的样子*/}
                            <Image style={icon_style} source={require('../../images/add_icon_large.png')} />
                    </TouchableOpacity>
                </View>
            </View>
        )
    }
    
    // 返回增加的图片
    renderPicItem(item, index) {
        return (
            <View key={index}>
                <TouchableOpacity
                    activeOpacity={.8}
                    >
                        <Image source={{uri: item}} />
                </TouchableOpacity>
            </View>
        )
    }
    ...
    
    
    
    
}


3. 封装的图片上传,请求后端接口的函数 uploadEquipImg,需要 formData 对象的格式,即【调用上传接口】,实现图片上传;

【文件 `TestAction` 内容如下:】

import {UploadRequest} from './util'; // 该函数内容在下面哈

...
// 图片上传
export const uploadEquipImg = async (params) => {
    let { formData } = params
    return await UploadRequest('自己的接口地址', formData)
}
...

4. 【fetch 上传】文件的封装;

【文件 `util` 内容如下:】

...

// 上传

export const UploadRequest(url, datas) {
    let BaseUrl = 'http://www.baidu.com'  // 域名地址,根据自己的修改
    
    const params = {
        method: 'POST',
        body: datas,
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        timeout: 5000 // 5s超时
    };

    return fetch(`${BaseUrl}${url}`, params)
        .then(response => response.json())
        .then(data => data)
        .catch(error => {
            return {error_code: -3, error_msg:'请求异常,请重试'}
        })
        
}

...

写给自己的随笔,有问题欢迎指出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章