UploadAvatar

UploadAvatar

import { useEffect, useRef, useState } from 'react';
import { Button, Image, Avatar, Row, Col , Modal } from 'antd';
import { UserOutlined } from '@ant-design/icons';

const UploadAvatar = () => {
  const videoWidth = '300'
  const videoHeight = '300'
  
  const [avatarUrl, setAvatarUrl] = useState<any>('')
  const [avatarPreViewUrl, setAvatarPreViewUrl] = useState<any>('')
  const [isShowTakePhoto, setIsShowTakePhoto] = useState<boolean>(false);
  const [isReTakePhoto, setIsReTakePhoto] = useState<boolean>(false)
  const inputRef = useRef<any>(null)
  const canvasCameraRef = useRef<any>(null)
  const videoCamera = useRef<any>(null)

  const uploadAvatarClick = () => {
    inputRef.current!.click()
  }

  const avatarFileChange = (e: any) => {
    const files = [...e.target.files];
		if (files.length === 0) return;
		let result = files.map(file => {
      let url = null;
      if (window?.createObjectURL != undefined) {
        url = window?.createObjectURL(file)
      } else if (window.URL != undefined) {
        url = window.URL.createObjectURL(file)
      } else if (window.webkitURL != undefined) {
        url = window.webkitURL.createObjectURL(file)
      }
      return url;
    })
    setAvatarUrl(result)
  }

  useEffect(() => {
    // 等拍照弹框显示后执行打开摄像头
    if(isShowTakePhoto) {
      openPhoto()
    }
  },[isShowTakePhoto])

  /** 开启摄像头 */
  const openPhoto = () => {
    const canvasCamera = canvasCameraRef.current
    const thisVideo = videoCamera.current
    const thisContext = canvasCamera?.getContext('2d')
    // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {}
    }
    // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
    // 使用getUserMedia,因为它会覆盖现有的属性。
    // 这里,如果缺少getUserMedia属性,就添加它。
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        // 首先获取现存的getUserMedia(如果存在)
        var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia
        // 有些浏览器不支持,会返回错误信息
        // 保持接口一致
        if (!getUserMedia) {
          return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
        }
        // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
        return new Promise(function (resolve, reject) {
          getUserMedia.call(navigator, constraints, resolve, reject)
        })
      }
    }
    var constraints = { audio: false, video: { width: videoWidth, height: videoHeight } }
    navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
      // 旧的浏览器可能没有srcObject
      if ('srcObject' in thisVideo) {
        thisVideo.srcObject = stream
      } else {
        // 避免在新的浏览器中使用它,因为它正在被弃用。
        thisVideo.src = window.URL.createObjectURL(stream)
      }
      thisVideo.onloadedmetadata = function (e) {
        thisVideo.play()
      }
    }).catch(err => {
      console.log(err)
    })
  }

  // base64转文件
  const dataURLtoFile  = (dataurl, filename) => {
    var arr = dataurl.split(',')
    var mime = arr[0].match(/:(.*?);/)[1]
    var bstr = atob(arr[1])
    var n = bstr.length
    var u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], filename, { type: mime })
  }

  /** 拍照并转换 */
  const takePhoto = () => {
    // 点击,canvas画图
    const canvasCamera = canvasCameraRef.current
    const thisVideo = videoCamera.current
    const thisContext = canvasCamera.getContext('2d')
    thisContext.drawImage(thisVideo, 0, 0, videoWidth, videoHeight)
    // 获取图片base64链接
    var image = canvasCamera.toDataURL('image/png')
    const file = dataURLtoFile(image, '')
    let url = '';
    if (window?.createObjectURL != undefined) {
      url = window?.createObjectURL(file)
    } else if (window.URL != undefined) {
      url = window.URL.createObjectURL(file)
    } else if (window.webkitURL != undefined) {
      url = window.webkitURL.createObjectURL(file)
    }
    setAvatarUrl(url)
    setAvatarPreViewUrl(url)
    if(thisVideo && thisVideo?.srcObject){
      thisVideo.srcObject.getTracks()[0].stop()
    }
    setIsReTakePhoto(false)
  }

  /** 重新拍照,重置临时图片 */
  const handleReTakePhoto = () => {
    setAvatarPreViewUrl('')
    setIsReTakePhoto(true)
    // setTimeout(() => {
    //   takePhoto()
    // }, 200)
  }

  useEffect(() => {
    if(isReTakePhoto) {
      openPhoto()
    }
  },[isReTakePhoto])

  const onCancel = () => {
    const thisVideo = videoCamera.current
    if(thisVideo && thisVideo?.srcObject){
      thisVideo.srcObject.getTracks()[0].stop()
    }
    setIsShowTakePhoto(false)
    setIsReTakePhoto(false)
    setAvatarPreViewUrl('')
  }
  
  return (
    <div>
      <div>
        {avatarUrl ? 
        <Image src={avatarUrl} style={{width: '100px', height: '100px', borderRadius: '10px'}} />
        :
        <Avatar shape="square" size={100} icon={<UserOutlined />} />
        }
      </div>
      <Row>
        <Col span={4}>
          <Button
            type='primary'
            onClick={uploadAvatarClick}
          >
            上传图片
          </Button>
          <input
            ref={inputRef}
            id="inputFile"
            type="file" 
            hidden
            onChange={avatarFileChange}
          />
        </Col>
        <Col span={4}>
          <Button
            type='primary'
            onClick={() => {
              setAvatarPreViewUrl('')
              setIsShowTakePhoto(true)
              setIsReTakePhoto(false)
            }}
          >
            拍照上传
          </Button>
        </Col>
      </Row>
      <Modal 
        title="拍照上传" 
        visible={isShowTakePhoto}
        onCancel={onCancel}
        footer={
          avatarPreViewUrl? 
          [
            <Button
              type='default'
              onClick={onCancel}
            >
              取消
            </Button>,
            <Button
              type='primary'
              onClick={handleReTakePhoto}
            >
              重新拍照
            </Button>,
            <Button
              type='primary'
              // onClick={hanldeOk}
            >
              确定
            </Button>
          ]:
          [
            <Button
              type='default'
              onClick={onCancel}
            >
              取消
            </Button>,
            <Button
              type='primary'
              onClick={takePhoto}
            >
              拍照
            </Button>
          ]
        }
      >
        {avatarPreViewUrl ? <Image src={avatarPreViewUrl} style={{width: '300px', height: '300px', borderRadius: '10px'}} />
        :
        <video ref={videoCamera} style={{width:`${videoWidth}`, height:`${videoHeight}`}} autoPlay></video>
        }
        <canvas ref={canvasCameraRef} width={300} height={300} style={{display: 'none', width: `${videoWidth}`, height: `${videoHeight}`}}></canvas>
      </Modal>
    </div>
  )
}
export default UploadAvatar;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值