model 中创建图片上传 API

  1. const Uploader = {
  2. add(file: any, filename: string) {
  3. const item = new AV.Object('Image')
  4. const avFile = new AV.File(filename, file)
  5. item.set('filename', filename)
  6. item.set('owner', AV.User.current())
  7. item.set('url', avFile)
  8. return new Promise((resolve, reject) => {
  9. item.save().then(
  10. (serverFile) => {
  11. console.log('保存成功')
  12. resolve(serverFile)
  13. },
  14. (error) => {
  15. console.log('保存失败')
  16. reject(error)
  17. }
  18. )
  19. })
  20. },
  21. }

store 中创建 ImageStore, 用于管理图片数据

  1. import { makeObservable, observable, action } from 'mobx'
  2. import { Uploader } from '../models'
  3. class ImageStore {
  4. @observable filename = ''
  5. @observable file: any = null
  6. @observable isUploading = false
  7. @observable serverFile: any = null
  8. constructor() {
  9. makeObservable(this)
  10. }
  11. @action setFilename(newFilename: string) {
  12. this.filename = newFilename
  13. }
  14. @action setFile(newFile: any) {
  15. this.file = newFile
  16. }
  17. @action upload() {
  18. this.isUploading = true
  19. return new Promise((resolve, reject) => {
  20. Uploader.add(this.file, this.filename)
  21. .then((serverFile: any) => {
  22. this.serverFile = serverFile
  23. resolve(serverFile)
  24. })
  25. .catch((err: any) => {
  26. console.log('上传失败')
  27. reject(err)
  28. })
  29. .finally(() => {
  30. this.isUploading = false
  31. })
  32. })
  33. }
  34. }
  35. export default new ImageStore()

原生 input 实现简易上传

  1. import { MutableRefObject, useRef } from 'react'
  2. import { useStore } from '../store'
  3. const Uploader = () => {
  4. const inputRef = useRef() as MutableRefObject<HTMLInputElement>
  5. const { ImageStore } = useStore()
  6. const handleUpload = () => {
  7. if (inputRef.current.files && inputRef.current.files.length > 0) {
  8. ImageStore.setFile(inputRef.current.files[0])
  9. ImageStore.setFilename(inputRef.current.files[0].name)
  10. ImageStore.upload()
  11. .then((file) => console.dir(file))
  12. .catch((err) => {
  13. console.error(err)
  14. })
  15. }
  16. }
  17. return (
  18. <>
  19. <h2>文件上传</h2>
  20. <input type="file" ref={inputRef} onChange={handleUpload} />
  21. </>
  22. )
  23. }
  24. export default Uploading

改用 antd 实现图片上传

使用 Upload 组件, 上传逻辑写在 beforeUpload 属性中

  1. import { MutableRefObject, useRef } from 'react'
  2. import { useStore } from '../store'
  3. import { Upload } from 'antd';
  4. import { InboxOutlined } from '@ant-design/icons';
  5. const { Dragger } = Upload;
  6. const Uploader = () => {
  7. const { ImageStore } = useStore()
  8. const props = {
  9. showUploadList: false,
  10. beforeUpload: (file:any) => {
  11. ImageStore.setFile(file)
  12. ImageStore.setFilename(file.name)
  13. ImageStore.upload()
  14. .then((file) => console.dir(file))
  15. .catch((err) => {
  16. console.error(err)
  17. })
  18. return false;
  19. },
  20. }
  21. return (
  22. <>
  23. <h2>文件上传</h2>
  24. <Dragger {...props}>
  25. <p className="ant-upload-drag-icon">
  26. <InboxOutlined />
  27. </p>
  28. <p className="ant-upload-text">Click or drag file to this area to upload</p>
  29. <p className="ant-upload-hint">
  30. Support for a single or bulk upload. Strictly prohibit from uploading company data or other
  31. band files
  32. </p>
  33. </Dragger>
  34. <div>
  35. <h2>保存地址</h2>
  36. {ImageStore.serverFile ? ImageStore.serverFile.attributes.url.attributes.url : ''}
  37. </div>
  38. </>
  39. )
  40. }
  41. export default Uploader

上传结果展示

  1. <div>
  2. {ImageStore.serverFile
  3. ? (<Result>
  4. <h2>上传结果</h2>
  5. <dl>
  6. <dt>线上地址</dt>
  7. <dd><a target="_blank" href={ImageStore.serverFile.attributes.url.attributes.url} rel="noreferrer">{ImageStore.serverFile.attributes.url.attributes.url}</a></dd>
  8. <dt>文件名</dt>
  9. <dd><input className="filename" type="text" value={ImageStore.filename} readOnly /></dd>
  10. <dt>图片预览</dt>
  11. <dd>
  12. <img src={ImageStore.serverFile.attributes.url.attributes.url} alt="" />
  13. </dd>
  14. <dt>更多尺寸</dt>
  15. <dd>...</dd>
  16. </dl>
  17. </Result>)
  18. : ''}
  19. </div>
  1. const Result = styled.div`
  2. margin-top: 20px;
  3. > dl {
  4. border: 1px dashed #6ebcfc;
  5. background: #fafafa;
  6. padding: 20px;
  7. .filename {
  8. border: 1px solid #999;
  9. width: 100%;
  10. padding: 4px;
  11. &:focus {
  12. outline: none;
  13. }
  14. }
  15. > dt {
  16. padding-bottom: 6px;
  17. }
  18. a {
  19. display: inline-block;
  20. width: 100%;
  21. border: 1px solid #999;
  22. padding: 4px;
  23. white-space: wrap;
  24. word-wrap:break-word;
  25. background: white;
  26. }
  27. img {
  28. max-height: 280px;
  29. max-width: 100%;
  30. object-fit: contain;
  31. }
  32. }
  33. `

限制图片的格式和大小

在 Dragger 组件的 beforeUpload 属性中添加限制

  1. beforeUpload: (file: any) => {
  2. ImageStore.setFile(file)
  3. ImageStore.setFilename(file.name)
  4. if (!/(svg$)|(png$)|(jpg$)|(jpeg$)|(gif$)/gi.test(file.type)) {
  5. message.error('仅支持 png/svg/jpg/jpeg/gif 格式的图片')
  6. return false
  7. }
  8. if (file.size > 2048 * 1024) {
  9. message.error('图片最大支持2M')
  10. return false
  11. }
  12. ImageStore.upload()
  13. .then((file) => console.dir(file))
  14. .catch((err) => {
  15. console.error(err)
  16. })
  17. return false
  18. },