鸿蒙开发之上传图片

506 阅读1分钟

简介背景

在使用任何一个APP的时候, 登录之后总有个人信息功能, 个人信息里面我们需要使用好看的头像, 这样就需要用户自定义去获取本地图片上传使用.

为什么要封装上传图片代码

在鸿蒙开发中没有现成的上传图片的代码, 如果实现一个完整的代码, 需要使用上下文以及fs文件管理器将用户相册拷贝到应用沙箱中, 使用internel://cache这种路径进行获取图片路径. 这也是鸿蒙因为没有操作用户相册的权限导致的. 针对这种现象我封装了两种图片上传的代码.

使用HTTP方式上传图片

  1. 选择本地图片
pickerAvatar() {
 const photoSelectOptions = new picker.PhotoSelectOptions()
 photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
 photoSelectOptions.maxSelectNumber = 1

 const photoViewPicker = new picker.PhotoViewPicker()
 photoViewPicker.select(photoSelectOptions).then(result => {
   console.log('mylog->photoViewPicker', JSON.stringify(result.photoUris))
   // 1. 得到文件路径
   this.URI = result.photoUris[0]
   if (this.URI) {
     this.uploadAvatar()
   }
 })
}
  1. 将图片拷贝到沙箱 -> 调用上传接口进行上传
uploadAvatar() {
  try {
    this.loading = true
    // 2. 拷贝到应用沙箱中
    const context = getContext(this) as common.UIAbilityContext;
    const type = 'jpg'
    const filenamepre = Date.now().toString()
    const filename = filenamepre + '.' + type
    const newFilePath = context.cacheDir + '/' + filename
    console.log('mylog->URI:', this.URI)

    fs.open(this.URI, fs.OpenMode.READ_ONLY).then(file => {
      console.log('mylog->file:', file.fd)
      fs.copyFile(file.fd, newFilePath).then(() => {
        console.info('mylog->copy success', `internal://cache/` + filename)
        // 3. 上传
        const config: request.UploadConfig = {
          url: '', // 这里是上传接口路径, 自行修改
          method: 'POST',
          header: {
            'Accept': '*/*',
            'Authorization': `Bearer ${this.user.token}`,
            'Content-Type': 'multipart/form-data'
          },
          files: [{ name: 'file', uri: `internal://cache/` + filename, type: type, filename: filename }],
          data: []
        }

        request.uploadFile(context, config).then(task => {
          task.on('progress', (uploadedSize: number, totalSize: number) => {
            console.log('mylog->size:', uploadedSize.toString(), '/', totalSize)
            if (uploadedSize === totalSize) {
              this.getUserInfo()
            }
          })

          task.on('fail', (taskStates: Array<request.TaskState>) => {
            console.log("mylog->upOnFail taskState:" + JSON.stringify(taskStates));

          })

        }, (err: BusinessError) => {
          console.log('mylog-> upload err', JSON.stringify(err))
        })

      }).catch((err: BusinessError) => {
        console.log('mylog->copyerr', JSON.stringify(err))
      })
    }).catch((err: BusinessError) => {
      console.log('mylog->openerr', JSON.stringify(err))
    })
  } catch (err) {
    console.log('mylog->err', JSON.stringify(err))
  }
}
  1. 请求userInfo接口更行头像
getUserInfo() {
  hdHttp.get<userInfoData>('userInfo').then(res => {
    console.log('mylog->userInfo', JSON.stringify(res))
    this.user.avatar = res.data.avatar ? res.data.avatar : ''
    // AppStorage.Set('user', JSON.stringify(this.user))
    authStore.setUser(this.user)
    this.loading = false
    promptAction.showToast({ message: '更新头像成功' })
  })
}

最后在调用一下

Image()
.onClick(() => {
    // 选择头像并上传this.pickerAvatar()
    this.pickerAvatar()
})

使用Axios方式上传图片

  1. 拉起用户相册选择
let photoSelectOption = new picker.PhotoSelectOptions()
photoSelectOption.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
photoSelectOption.maxSelectNumber = 1
let photoPicker = new picker.PhotoViewPicker()
const res: picker.PhotoSelectResult = await photoPicker.select(photoSelectOption)
this.uris = res.photoUris
  1. 将选择好的图片拷贝到沙箱中
const fileType = 'jpg'
const fileName = Date.now() + '.' + fileType
const cacheFilePath = this.context.cacheDir + '/' + fileName
const file = fs.openSync(this.uris[0], fs.OpenMode.READ_ONLY)
fs.copyFileSync(file.fd, cacheFilePath)
  1. 从沙箱缓存中获取图片路径
let formData = new FormData()
let files: Array<request.File> = [
  {
    filename: fileName,
    type: fileType,
    name: 'image',
    uri: `internal://cache/${fileName}`
  }
]
console.info('result---->', JSON.stringify(files[0].uri))
formData.append('img', files[0].uri, {
  fileType: fileType,
  fileName: fileName
})
  1. 调用上传接口将图片上传到服务器
axios<string, AxiosResponse<string>, FormData>({
  url: 'https://hmajax.itheima.net/api/uploadimg',
  method: 'POST',
  data: formData,
  headers: {
    'Content-Type': 'multipart/form-data' // 文件上传
  },
  context: this.context,
  // 上传进度, 可以使用页面组件显示在页面上, 方便用户查看上传进度
  onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
    let total = progressEvent.total ?? 0
    this.progressValues = {
      loaded: progressEvent.loaded,
      total: progressEvent.total,
      rate: Math.ceil(progressEvent.loaded / total * 100)
    }
    console.info('result---->progressEvent', JSON.stringify(this.progressValues))
  }
})
  .then((res: AxiosResponse<string>) => {
    this.imagePath = JSON.parse(JSON.stringify(res.data)).data.url
    console.info("result---->url: " + this.imagePath);
  }).catch((err: AxiosError) => {
  console.error("result---->error:" + JSON.stringify(err));
})

最后在调用一下

Image(this.imagePath ? this.imagePath : $r('app.media.icon'))
  .width(70)
  .height(70)
  .borderRadius(35)
  .border({ width: 1, color: Color.White })
  .onClick(() => {
    // 上传头像
    this.getAvatar()
  })