react+koa實現圖片上傳功能

技術棧

koa2 + react16.8
github 地址連接javascript

項目步驟

  • 前端開發

    1.建立react app
    yarn create react-app my-app
    2.用material-ui編寫頁面,代碼以下html

    <form action="/upload"  method="post" encType="multipart/form-data" style={{width:'100%'}}>
      <div>
        <input
            accept="image/*"
            className={classes.input}
            id="contained-button-file"
            multiple
            type="file"
            onChange={uploadImg}
    
        />
        <label htmlFor="contained-button-file">
          <Button variant="contained"
                  component="span"
                  className={classes.button}
          >
            添加圖片
          </Button>
        </label>
        <GridList cellHeight={100} className={classes.gridList} cols={3}>
          {/*{console.log('html',values.images&&values.images)}*/}
          { values.images && values.images.map((item,index) => (
              <GridListTile key={index}
                            cols={item.cols || 1}
                            data-index = {index}
              >
    
                <strong>{item.name}</strong>
                <a href="javascript:void(0)"
                   className="upload-delete"
                   title="刪除"
                   data-index = {index}
                   onClick={deleteImg}
                >刪除{index}</a>
                <br/>
                <img src={item.thumb} />
              </GridListTile>
          ))}
    
        </GridList>
    
      </div>
    </form>
    {
      values.images &&values.images.length ?
    
          <Button variant="contained"
                  color="primary"
                  style={{height:'40px',width:'20%'}}
                  className={classes.margin}
                  onClick={() => handleUpload()}>
            上傳圖片
          </Button>:''
    }

    3.其中須要用的函數代碼以下:前端

    const classes = useStyles();
    const [values, setValues] = React.useState({
      age: '',
      images:[],
      uploadHistory:[],
    });
    
    function uploadImg(e) {
      e.preventDefault();
      let target = e.target;
      let files = target.files;
      let count = files.length;
      for (let i = 0; i < count; i++) {
        files[i].thumb = URL.createObjectURL(files[i])
      }
      // convert to array
      //Array.prototype.slice.call(arguments)能將具備length屬性的對象(key值爲數字)轉成數組。
      // []是Array的示例,因此能夠直接使用[].slice()方法。
      files = Array.prototype.slice.call(files, 0);
      files = files.filter(function (file) {
        return /image/i.test(file.type)
      });
      setValues(oldValues => ({
        ...oldValues,
        images: values.images.concat(files)
      }));
    
    }
    
    const deleteImg = (e) => {
    
      let index = e.target.getAttribute('data-index');
      let result = values.images.splice(index,1);
    
      setValues(oldValues => ({
        ...oldValues,
        images: values.images
      }));
    };
    function handleUpload() {
      for (let i = 0, file; file = values.images[i]; i++) {
        ((file) => {
          let xhr = new XMLHttpRequest();
          if (xhr.upload) {
            // 上傳中
            console.log('上傳中')
            xhr.upload.addEventListener("progress", (e) => {
              // handleProgress(file, e.loaded, e.total, i);
            }, false);
    
            // 文件上傳成功或是失敗
            xhr.onreadystatechange = (e) => {
              if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                  console.log('handleSuccess'  ,file )
                  // handleSuccess(file, xhr.responseText);
                  // this.handleDeleteFile(file);
    
                  if (!values.images.length) {
                    //所有完畢
                    handleComplete();
                    console.log('所有上傳完成!');
                  }
                } else {
                  handleFailure(file, xhr.responseText);
                  console.log('上傳出錯!');
                }
              }
            };
    
            const form = new FormData();
            form.append("filedata", file);
            // 開始上傳
            xhr.open("POST", "/upload", true);
            // xhr.setRequestHeader("FILENAME", file.name);
            console.log('form',form);
            xhr.send(form);
          }
        })(file)
      }
    }
    //當上傳圖片的時候,若是還須要從前端日後端傳參數能夠使用`form.append("filedata", file);`的方法
  • 後端開發

1.koa搭建框架代碼:java

const Koa = require('koa');
const app = new Koa();
app.use(statics(
    path.join(__dirname,staticPath)
));
app.use(statics('.'));

app.use(bodyParser());

app.listen(9000); //後端接聽9000端口

2.前端引入靜態文件,這樣react,build好的文件直接和後端連接起來react

const statics = require('koa-static'); //使用koa-static
const staticPath = './build';
app.use(statics(
    path.join(__dirname,staticPath)
));
app.use(statics('.'));

3.get 和put 方法設置git

app.use(async(ctx, next) => {
    await next();
    ctx.response.type = 'text/html';
    // ctx.response.body = '<h1>Hello,koa2222!</h1>';
    //   console.log('ctx use',ctx.url,ctx.method);
    if(ctx.method === 'GET'){ //當請求時GET請求時
        ctx.body =ctx.response.body;
    }else if(ctx.url==='/' && ctx.method === 'POST'){ //當請求時POST請求時
        ctx.body=await parsePostData(ctx);
    }else{
        //其它請求顯示404頁面
        ctx.body='<h1>404!</h1>';
    }

});

function parsePostData( ctx ) {
    return new Promise((resolve, reject) => {
        try {
            let postdata = "";
            ctx.req.addListener('data', (data) => {
                postdata += data
            })
            ctx.req.addListener("end",function(){
                let parseData = parseQueryStr( postdata );
                resolve( parseData )
            })
        } catch ( err ) {
            reject(err)
        }
    })
}
function parseQueryStr( queryStr ) {
    let queryData = {};
    let queryStrList = queryStr.split('&');
    console.log( queryStrList );
    for (  let [ index, queryStr ] of queryStrList.entries()  ) {
        let itemList = queryStr.split('=');
        queryData[ itemList[0] ] = decodeURIComponent(itemList[1])
    }
    return queryData
}

4.跨域設置github

const cors = require('koa-cors');
app.use(cors());

5.圖片上傳api實現json

router.post('/upload',  async(ctx, next) => { //提交圖片接口
    var form = new multiparty.Form({uploadDir: './files/'});
    // 上傳完成後處理
    form.parse(ctx.req, function(err, fields, files) {
    //fields裏有前端append的參數
        if (err) {
            throw err;
        } else {
            //form.append ()的值在fields中
            processImg(ctx.req, ctx.res, files,fields).then(function(data) {
                console.log('hshsh')
                // 設置跨域
                // allowCross(ctx);
                // res.json({
                //     res: JSON.parse(data.filesTmp),
                //     relPath: data.relPath,
                // })
            }).catch(function(err) {
                console.log(err)
            });
        }
    });

});

function processImg(req, res, files,fields) {
    return new Promise(function(resolve, reject) {
        const _img = files.filedata[0];
        const uploadedPath = _img.path;
        const originalFilename = _img.originalFilename;
        let dstPath = './imgs/'+ originalFilename;
        // console.log('dstPath',dstPath);
        //  (目前的路徑,重命名後的路徑)重命名
        fs.rename(uploadedPath, dstPath, function(err) {
            if (err) {
                reject(err)
            } else {
                console.log('rename ok!');
            }
        });
    });
}

總結

前端:
1.material-ui地址:https://material-ui.com/ 它是React組件,實現了谷歌Material Design設計規範。世界上最流行的React界面框架。
2.圖片是file類型,須要轉數組Array.prototype.slice.call
3.當上傳圖片的時候,若是還須要從前端日後端傳參數能夠使用form.append("filedata", file);的方法
後端:
1.後端的form.parse方法的fields裏有前端append的參數;
2.跨域使用koa-cors
3.上傳的圖片名字不是圖片自己的名字,能夠fs.rename來從新命名
4.getput方法須要區分,能夠使用上文中的代碼。
5.koa-static能夠將react 中build後的文件同後端連接起來後端

相關文章
相關標籤/搜索