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:'請求異常,請重試'}
        })
        
}

...

寫給自己的隨筆,有問題歡迎指出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章