React+egg上传图片到阿里云OSS

首先去阿里云OSS控制台,创建bucket账号,得到accessKeyIdaccessKeySecret

egg项目配置OSS

下载egg-oss

npm i egg-oss --save-dev

配置oss

//config/config.default.js
config.oss = {
    
    
    client: {
    
    
      bucket: 'bucket',//创建bucket自定义的账号
      region: 'oss-cn-hangzhou',
      endpoint: "oss-cn-hangzhou.aliyuncs.com", 
      accessKeyId: 'accessKeyId',//创建bucket生成的accessKeyId
      accessKeySecret: 'accessKeyId',//创建bucket生成的accessKeySecret
      secure: true,
    },
  };
// config/plugin.js
  oss: {
    
    
    enable: true,
    package: 'egg-oss',
  }

生成接口

controller下新建upload.js文件


// app/controller/upload.js
'use strict';

const path = require('path');
const Controller = require('egg').Controller;

class UploadController extends Controller {
    
    
  /**
   * 上传文件
   */
  async uploadAvatar() {
    
    
    const {
    
     ctx } = this;

    let filePath;
    const stream = await ctx.getFileStream();
    if (stream.fields.filePath) {
    
    
      filePath = stream.fields.filePath + '/' + path.basename(stream.filename);
    } else {
    
    
      filePath = path.basename(stream.filename);
    }

    const result = await ctx.oss.put(filePath, stream);

    ctx.body = {
    
    
        data:{
    
    
            code: 200,
            message: '上传成功',
            data: {
    
     url: result.url },
        }
    };
  }
}

module.exports = UploadController;

配置接口路由

'use strict';

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
    
    
  const {
    
     router, controller, middleware } = app;
  router.post('/upload/uploadAvatar', controller.upload.uploadAvatar); 
};

这样我们就得到一个接口,名为:/upload/uploadAvatar.接下来让我们使用它

React项目调用接口

封装图片上传组件


import React, {
    
     useState, forwardRef, useImperativeHandle, useEffect } from 'react'
import {
    
     PlusOutlined } from '@ant-design/icons';
import {
    
     Modal, Upload } from 'antd';
// import type { UploadChangeParam } from 'antd/es/upload';
import type {
    
     RcFile, UploadFile, UploadProps } from 'antd/es/upload/interface';
import '../index.less'

const getBase64 = (file: RcFile): Promise<string> =>
  new Promise((resolve, reject) => {
    
    
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = (error) => reject(error);
  });

const JsImageUpload = ( props:any, ref:any ) => {
    
    
    const [previewOpen, setPreviewOpen] = useState(false);
    const [previewImage, setPreviewImage] = useState('');
    const [previewTitle, setPreviewTitle] = useState('');
    const [fileList, setFileList] = useState<UploadFile[]>([])
    const imgUrl = props?.urlData
    // console.log(imgUrl)
    useEffect(() => {
    
    
        if(imgUrl) {
    
    
            let obj = {
    
    
                uid: Math.floor(Math.random()*100)+"",
                name: Math.floor(Math.random()*100)+'',
                url: imgUrl
            }
            
            setFileList([obj])
        }
    }, [imgUrl])
    //解决异步回调的问题
    useEffect(() => {
    
    
    }, [fileList]);
    // 可以让父组件调用子组件的方法
    // 作用: 减少父组件获取子组件的DOM元素属性,只暴露给父组件需要用到的DOM方法
    // 参数1: 父组件传递的ref属性
    // 参数2: 返回一个对象,父组件通过ref.current调用对象中方法
    useImperativeHandle(ref, () => ({
    
    
        
    }));
    const handleCancel = () => setPreviewOpen(false);

    const handlePreview = async (file: UploadFile) => {
    
    
        if (!file.url && !file.preview) {
    
    
            file.preview = await getBase64(file.originFileObj as RcFile);
        }

        setPreviewImage(file.url || (file.preview as string));
        setPreviewOpen(true);
        setPreviewTitle(file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1));
    };

    const handleChange: UploadProps['onChange'] = ({
    
     fileList: newFileList }) => {
    
    
        setFileList(newFileList);
        props.uploadImgData(newFileList, props.urlIdx)
    }

    const uploadButton = (
        <div>
            <PlusOutlined />
            <div style={
    
    {
    
     marginTop: 8 }}>产品图片上传</div>
        </div>
    );
    return (
        <div className="upLoadPictureItem"> 
            <Upload
                action="http://127.0.0.1:7001/upload/uploadAvatar"
                listType="picture-card"
                fileList={
    
    fileList}
                onPreview={
    
    handlePreview}
                onChange={
    
    handleChange}
            >
                {
    
    fileList.length >= 1 ? null : uploadButton}
            </Upload>
            <Modal open={
    
    previewOpen} title={
    
    previewTitle} footer={
    
    null} onCancel={
    
    handleCancel}>
                <img alt="example" style={
    
    {
    
     width: '100%' }} src={
    
    previewImage} />
            </Modal>
        </div>
    )
}

export default forwardRef(JsImageUpload)

前端父组件调用

import JsImageUpload from '@/components/content/jsImageUpload';
import React, {
    
     useRef, useState, forwardRef, useImperativeHandle } from 'react';
import {
    
     Button, Form, Input, InputNumber, message, Modal, Popover, Tree, Radio, Breadcrumb, Card, Select, } from 'antd';
import {
    
     useSelector, shallowEqual } from "react-redux";
import axios from '@/services/index'
import {
    
     CloseCircleOutlined, PlusOutlined } from '@ant-design/icons';
import './index.less'
import JsImageUpload from '@/components/content/jsImageUpload';
import {
    
     deepCopy } from '@/utils/devUtils';
import {
    
     useSearchParams, useLocation, useNavigate } from 'react-router-dom';


//图片上传父子组件交互使用
const ProductContent = ( props:any, ref:any ) => {
    
    

	let imgMethodRef = useRef<any>(null);
	// 可以让父组件调用子组件的方法
    // 作用: 减少父组件获取子组件的DOM元素属性,只暴露给父组件需要用到的DOM方法
    // 参数1: 父组件传递的ref属性
    // 参数2: 返回一个对象,父组件通过ref.current调用对象中方法
    useImperativeHandle(ref, () => ({
    
    
        
    }));
    //获取图片上传子组件url
    const uploadImgData = (urlArr:any, idx:any)=>{
    
    
        const arr = deepCopy(detail)//深拷贝方法
        const urlObj = urlArr[0]
        
        if(urlObj && urlObj.status == "done" && urlObj.response.data.code == 0) {
    
    
            const url = urlObj.response.data.data.url
            arr[idx].url = url
            setDetail(arr)
        }
    } 
	<Form.Item
	     label=""
	 >
	     {
    
    detail.map((item, index) => (
	         <Card title="" 
	             key={
    
    item.id} 
	             extra={
    
    
	                 detail && detail.length > 1 && 
	                 <a href="#" 
	                 onClick={
    
    (index:any)=>deleteRowDetail(index)}>
	             <CloseCircleOutlined /></a>} 
	             style={
    
    {
    
     width: 600 }}>
	             <div className="card">
	                 <div>
	                     <JsImageUpload 
	                     uploadImgData={
    
    uploadImgData} 
	                     urlData={
    
    item.url} //图片回显
	                     urlIdx={
    
    index} //当前图片在的下标用于保存
	                     ref={
    
    imgMethodRef} />
	                 </div>
	             </div>
	             
	         </Card>
	     ))}
	 </Form.Item>
})
export default forwardRef(ProductContent)

效果图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/chenacxz/article/details/129790012