React Native Expo项目上传文件

Index.js:

javascript 复制代码
import React from 'react'
import {
  ScrollView,
  View,
  TouchableWithoutFeedback,
  Text,
  Image,
} from 'react-native'
import { WebView } from 'react-native-webview'
import style from './style.js'
import { Icon } from '../../../component/light'
import { Divider, LinearProgress, Button, Input, Dialog } from '@rneui/themed'
import useList from './useList.js'

export default function Index(props) {
  const {
    username,
    emailCode,
    isSendEmail,
    count,
    avatar,
    nickname,
    password,
    code,
    visible,
    isLoading,
    captcha,
    visible1,
    usernameEl,
    setEmailCode,
    handleSendEmail,
    setNickname,
    setPassword,
    setCode,
    toggleDialog1,
    handleInput,
    handleLogin,
    handleNav,
    handleVisilbe,
    handleUploadAvatar,
    getCaptcha,
    pickFile,
  } = useList(props)

  return (
    <ScrollView style={style.mRegisterWrap}>
      <LinearProgress
        style={[style.mLoading, isLoading ? style.mLoadingActive : {}]}
        color="primary"
      />
      <View style={style.mRegisterInner}>
        <View style={style.mRegisterRow}>
          <Input
            label="邮箱"
            style={style.mRegisterInput}
            labelStyle={style.mRegisterLabelStyle}
            value={username}
            onChangeText={handleInput}
            placeholder="邮箱"
            // autoFocus
            ref={usernameEl}
            rightIcon={
              <Icon
                name={'help'}
                onPress={toggleDialog1}
                style={style.mInpntRightIcon}
              ></Icon>
            }
          ></Input>
        </View>
        <View style={style.mRegisterRow}>
          <Input
            label="邮箱验证码"
            style={style.mRegisterInput}
            labelStyle={style.mRegisterLabelStyle}
            value={emailCode}
            onChangeText={setEmailCode}
            placeholder="邮箱验证码"
            rightIcon={
              isSendEmail ? (
                <Button
                  title={`${count}秒后重新发送`}
                  disabled
                  containerStyle={style.mSendEmailBtn}
                />
              ) : (
                <Button
                  title="发送"
                  containerStyle={style.mSendEmailBtn}
                  onPress={handleSendEmail}
                />
              )
            }
          ></Input>
        </View>
        <View style={style.mRegisterRow}>
          <View style={style.mRegisterAvavtarTextWrap}>
            <Text style={style.mRegisterAvavtarText}>头像</Text>
          </View>
          {avatar ? (
            <TouchableWithoutFeedback onPress={handleUploadAvatar}>
              <Image
                source={{ uri: avatar }}
                style={style.mRegisterAvatar}
              ></Image>
            </TouchableWithoutFeedback>
          ) : (
            <View style={style.mRegisterUploadIcoWrap}>
              <Icon
                name={'add'}
                onPress={handleUploadAvatar}
                style={style.mRegisterUploadIcon}
              ></Icon>
            </View>
          )}
        </View>
        <View style={style.mRegisterRow}>
          <Input
            label="昵称"
            style={style.mRegisterInput}
            labelStyle={style.mRegisterLabelStyle}
            value={nickname}
            onChangeText={setNickname}
            placeholder="昵称"
          ></Input>
        </View>
        <View style={style.mRegisterRow}>
          <Input
            label="密码"
            style={style.mRegisterInput}
            labelStyle={style.mRegisterLabelStyle}
            value={password}
            onChangeText={setPassword}
            placeholder="密码"
            secureTextEntry={!visible}
          ></Input>
          <Icon
            name={visible ? 'show' : 'close'}
            onPress={handleVisilbe}
            style={style.mRegisterPasswordIcon}
          ></Icon>
        </View>
        <View style={style.mRegisterRow}>
          <Input
            label="验证码"
            style={style.mRegisterInput}
            labelStyle={style.mRegisterLabelStyle}
            value={code}
            onChangeText={setCode}
            placeholder="验证码"
          ></Input>
        </View>
        <View style={style.mRegisterCodeWrap}>
          <TouchableWithoutFeedback onPress={getCaptcha}>
            <WebView
              originWhitelist={['*']}
              source={{ html: captcha }}
            ></WebView>
          </TouchableWithoutFeedback>
        </View>

        <View style={[style.mRegisterBtnWrap]}>
          <Button onPress={handleLogin} type="solid" title="注册"></Button>
        </View>
        <View style={style.mRegisterMoreBtnWrap}>
          <Button
            containerStyle={style.mRegisterMoreBtn}
            onPress={() => handleNav('Login')}
            title="登录"
            type="clear"
          ></Button>
          <Button
            containerStyle={style.mRegisterMoreBtn}
            onPress={() => handleNav('IndexForTab')}
            title="游客"
            type="clear"
          ></Button>
        </View>
        <Divider width={1}></Divider>
        <Button title="上传文件" onPress={pickFile} />

        <Text style={style.mRegisterText}>注册</Text>

      </View>
      <Dialog isVisible={visible1} onBackdropPress={toggleDialog1}>
        <Dialog.Title title="提示" />
        <Text>某些用户的邮件会发送到垃圾箱</Text>
      </Dialog>
    </ScrollView>
  )
}

useList.js:

javascript 复制代码
import { useState, useRef, useEffect } from 'react'
import Api from '../../../api'
import Constants from 'expo-constants'
import Toast from 'react-native-root-toast'
import { checkEmail } from '../../../utils/tools'
import AsyncStorage from '@react-native-async-storage/async-storage'
import * as ImagePicker from 'expo-image-picker'
import * as DocumentPicker from 'expo-document-picker'

let timer
export default function useList(props) {
  const [username, setUsername] = useState('')
  const [emailCode, setEmailCode] = useState('')
  const [isSendEmail, setIsSendEmail] = useState(false)
  const [count, setCount] = useState(0)
  const [emailId, setEmailId] = useState('')
  const [avatar, setAvatar] = useState(null)
  const [nickname, setNickname] = useState('')

  const [password, setPassword] = useState('')
  const [code, setCode] = useState('')
  const [visible, setVisible] = useState(false)
  // eslint-disable-next-line
  const [isLoading, setIsLoading] = useState(false)
  const [captchaId, setCaptchaId] = useState('')
  const [captcha, setCaptcha] = useState('')
  const [visible1, setVisible1] = useState(false)
  const usernameEl = useRef(null)

  const { navigation } = props

  const toggleDialog1 = () => {
    setVisible1(!visible1)
  }
  const handleInput = (e) => {
    setUsername(e)
  }

  const handleSendEmail = () => {
    const { isEmail, message } = checkEmail(username)
    if (username.trim() === '') {
      Toast.show('邮箱不能为空', {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    } else if (isEmail === false) {
      Toast.show(message, {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    }

    Api.h5.userSendEmailCode({ username }).then((res) => {
      if (res.code === 200) {
        setEmailId(res.data.emailId)
        Toast.show(res.message, {
          duration: 3000,
          position: Toast.positions.CENTER,
        })
        setCount(Constants.manifest.extra.REACT_APP_MODE === 'dev' ? 6 : 180)
        setIsSendEmail(true)
        console.log('send11', res.data.emailId)
      }
    })
  }

  const handleLogin = () => {
    const { isEmail, message } = checkEmail(username)

    if (username.trim() === '') {
      Toast.show('用户名不能为空', {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    } else if (isEmail === false) {
      Toast.show(message, {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    } else if (password.trim() === '') {
      Toast.show('密码不能为空', {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    } else if (code.trim() === '') {
      Toast.show('验证码不能为空', {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    } else if (!emailId) {
      Toast.show('请获取邮箱验证码', {
        duration: 3000,
        position: Toast.positions.CENTER,
      })
      return
    }

    Api.h5
      .userAiAdd({
        username,
        emailCode,
        emailId,
        nickname,
        password,
        code,
        captchaId,
      })
      .then((res) => {
        if (res.code === 200) {
          navigation.navigate('Login')
        }
      })
  }

  const handleNav = (path) => {
    navigation.navigate(path)
  }

  const handleVisilbe = () => {
    setVisible(!visible)
  }

  const handleUploadAvatar = async () => {
    try {
      let result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.All,
        base64: true,
        //allowsEditing: true,
        //aspect: [4, 3],
        //quality: 1,
      })
      if (!result.canceled) {
        const formData = new FormData()
        let uri = result.assets[0].uri
        let uriArr = uri.split('/')
        let name = uriArr[uriArr.length - 1]
        console.log(uri)
        setAvatar(uri)
        formData.append('file', {
          uri,
          name,
          //type: result.assets[0].type,
          type: 'image/jpeg',
        })
        Api.h5
          .uploadFile(formData)
          .then((res) => {
            console.log(res)
            if (res.code === 200) {
              console.log('成功')
              Toast.show('上传成功', {
                duration: 3000,
                position: Toast.positions.CENTER,
              })
            }
          })
          .catch((err) => {
            Toast.show('上传失败', {
              duration: 3000,
              position: Toast.positions.CENTER,
            })
          })
      } else {
        console.log('取消文件选择')
      }
    } catch (error) {
      console.log('选择文件时出错', error)
    }
  }

  const getCaptcha = () => {
    console.log('captcha')
    Api.h5.userCaptcha({}).then((res) => {
      if (res.code === 200) {
        const { captchaId, captcha } = res.data
        let svg = captcha
        let height = svg.indexOf('height')
        let width = svg.indexOf('width')
        let step1 = svg.slice(0, height + 8)
        let step2 = svg.slice(height + 8 + 2)
        svg = `${step1}150${step2}`
        let step3 = svg.slice(0, width + 5)
        let step4 = svg.slice(width + 8 + 3)
        svg = `${step3}450${step4}`
        let html = `<div style="text-align:center;width:100%;overflow:hidden;">${svg}</div>`
        setCaptcha(html)
        setCaptchaId(captchaId)
      }
    })
  }

  const pickFile = async () => {
    try {
      const result = await DocumentPicker.getDocumentAsync()

      if (result.type === 'success') {
        // 执行文件上传的逻辑
        console.log(result.uri) // 上传文件的URI
        console.log(result.name) // 上传文件的名称
        console.log(result.size) // 上传文件的大小
        console.log(result.mimeType) // 上传文件的类型

        const formData = new FormData()
        let uri = result.uri
        let uriArr = uri.split('/')
        let name = uriArr[uriArr.length - 1]

        formData.append('file', {
          uri: result.uri,
          name: result.name,
          type: result.mimeType,
        })
        Api.h5
          .uploadFile(formData)
          .then((res) => {
            console.log(res)
            if (res.code === 200) {
              console.log('成功')
              Toast.show('上传成功', {
                duration: 3000,
                position: Toast.positions.CENTER,
              })
            }
          })
          .catch((err) => {
            Toast.show('上传失败', {
              duration: 3000,
              position: Toast.positions.CENTER,
            })
          })
      } else {
        console.log('取消文件选择')
      }
    } catch (error) {
      console.log('选择文件时出错', error)
    }
  }

  useEffect(() => {
    ;(async () => {
      // 请求权限
      const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync()
      if (status !== 'granted') {
        console.log('拒绝访问图片库权限!')
      } else {
        console.log('已经获得访问图片库权限123!')
      }
    })()
  }, [])

  useEffect(() => {
    getCaptcha()
  }, [])

  useEffect(() => {
    clearTimeout(timer)
    timer = setTimeout(() => {
      if (count > 1) {
        setCount(count - 1)
      } else {
        setIsSendEmail(false)
      }
    }, 1000)
    // eslint-disable-next-line
  }, [count])

  useEffect(() => {
    //usernameEl.current.focus()
    //console.log(666, usernameEl.current.isFocused())
  }, [])

  useEffect(() => {
    Api.h5.uploadGetTokenForH5().then(async (res) => {
      if (res.code === 200) {
        await AsyncStorage.setItem('qiniuUploadTokenForH5', res.data.token)
        const qiniuUploadTokenForH5 = await AsyncStorage.getItem(
          'qiniuUploadTokenForH5'
        )
        console.log('qiniuUploadTokenForH5', qiniuUploadTokenForH5)
      }
    })
  }, [])

  return {
    username,
    emailCode,
    isSendEmail,
    count,
    avatar,
    nickname,
    password,
    code,
    visible,
    isLoading,
    captcha,
    visible1,
    usernameEl,
    setEmailCode,
    handleSendEmail,
    setNickname,
    setPassword,
    setCode,
    toggleDialog1,
    handleInput,
    handleLogin,
    handleNav,
    handleVisilbe,
    handleUploadAvatar,
    getCaptcha,
    pickFile,
  }
}

app.json:

javascript 复制代码
{
  "expo": {
    "plugins": [
      [
        "expo-document-picker",
        {
          "iCloudContainerEnvironment": "Production"
        }
      ]
    ]
  }
}

参考链接:

https://chat.xutongbao.top/

https://docs.expo.dev/versions/latest/sdk/document-picker/

https://blog.csdn.net/xutongbao/article/details/131981469?spm=1001.2014.3001.5501

相关推荐
夏河始溢13 分钟前
一七八、Node.js PM2使用介绍
前端·javascript·node.js·pm2
熊的猫29 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie2 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
工业甲酰苯胺2 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
程序员爱技术6 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
悦涵仙子7 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
兔老大的胡萝卜7 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
cs_dn_Jie10 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉