前端筆記之React(八)上傳&圖片裁切

  • 2019 年 10 月 3 日
  • 筆記

上傳

formidable天生可以處理上傳的文件,非常簡單就能持久上傳的文件。

今天主要講解的是,前後端的配合套路。

上傳分為同步、非同步。同步公司使用非常多,非同步我們也會講解。

1.1 先看一下antd中的Form和程式碼校驗

我們看antd中的Form組件,https://ant.design/components/form-cn/

 

所謂的裝飾器指的是將一個組件作為一個函數的參數。

MyForm是一個標準的組件,要用Form.create()()裝飾一下。

const WrappedRegistrationForm = Form.create()(MyForm);

裝飾器,就是函數後面有兩個圈比如,getFieldDecorator()()。第一個圈裡寫如何裝飾,第二個圈裡寫被裝飾的組件。

慢慢去分析人家的API,慢慢看,慢慢琢磨。


1.2 上傳前端套路和formidable的實現 

 <input type="file"/>

我們現在要製作提交,前端介面必須滿足幾點:

1)必須要用form標籤嵌套,這是一個表單,不是一個ajax程式;

2)表單的method屬性必須是POST

3)必須有enttype,值是“multipart/form-data”,什麼意思?下面有圖片講解

4) file控制項必須有name屬性

5)必須有提交按鈕

<form action="/uploadAvatar" method="POST" enctype ="multipart/form-data">         <input type="file" name="avatar" />         <input type="submit" name="上傳"/>  </form>

 

後端實現上傳非常簡單(當然工作實現上傳肯定不是你的事情):

//上傳圖片的路由  app.post("/uploadAvatar" , function(req,res){      var form = new formidable.IncomingForm();      //定義上傳的文件夾名字      form.uploadDir = path.resolve(__dirname , "./www/uploads");      //保留文件拓展名      form.keepExtensions = true;        form.parse(req , function(err , fileds , files){          res.send("成功");      });  });

文件名會被隨機改名。

 

如何得到上傳之後的隨機名字?

form.parse(req , function(err , fileds , files){      console.log(files.avatar.path);       res.send("成功");  });

提煉真正的文件名,而不包括完整路徑:

 var base = path.parse(files.avatar.path).base;

1.3 抑制頁面跳轉

當點擊submit按鈕的時候,瀏覽器的默認邏輯就是跳轉到action的頁面。

除非你用非同步。但是,非同步Ajax瀏覽器很少支援,IE10開始支援。

<form action="/uploadAvatar" method="POST" enctype="multipart/form-data">         <input type="file" name="avatar" />         <input type="submit" name="上傳"/>  </form>

在同步的時候,我們就要使用奇淫技巧。

 

使用iframe,框架,內嵌小電視。

<iframe src="http://www.baidu.com" frameborder="1"></iframe>

在小電視中的所有跳轉,都是關閉到小電視中的。

我們的表單就可以被內簽到小電視中,此時即使submit發生了跳轉,也是在小電視中的跳轉。

 

直接使用靜態頁面,在www裡面創建pages文件夾:

 

一切都將發生在小電視中,頁面跳轉被抑制了。

 


1.4 上傳按鈕

並且我們希望用戶選擇完圖片之後,就能立即上傳,而不用多一次提交的點擊。

用模擬事件就行了

 

所有的內嵌頁面,將不能天生擁有外部的window的作用域。

alert($)    alert(window.parent.$)

jQuery有問題,只能得到引包的window域中的dom

 

模擬事件:

  <script>          $("#pencile").click(function(){              $("#file_btn").trigger("click");          });            //一旦file被改變,就上傳          $("#file_btn").bind("change" , function(){              $("form")[0].submit();          });      </script>

1.5 回調函數

上傳成功之後調用父window中的js

form.parse(req , function(err , fileds , files){       var base = path.parse(files.avatar.path).base;       res.send("<script>window.parent.success_upload_avatar(" + base + ");</script >")   });

二、圖片的裁切

2.1 gm的安裝

我們要安裝gm這個東西,它是C++寫出來的一個軟體,不是npm包。

http://www.graphicsmagick.org/

 

GraphicsMagick is the swiss army knife of image processing.

小而功能多

 

下載:ftp://ftp.graphicsmagick.org/pub/GraphicsMagick/windows/

按自己的位數進行安裝:

 

將安裝路徑,上圖所示的這個文件夾的路徑,添加到系統的環境變數中

為了檢查環境變數是否設置正確,要輸入

gm -version


2.2 gmnodejs工作

https://www.npmjs.com/package/gm

此時要安裝gm這個npm

npm install --save gm

nodejs就能夠剪裁圖片、編輯圖片、美化圖片等等操作。

 

nodejs程式

var gm = require("gm");  //上傳圖片的路由  app.post("/uploadAvatar" , function(req,res){      var form = new formidable.IncomingForm();      //定義上傳的文件夾名字      form.uploadDir = path.resolve(__dirname , "./www/uploads");      //保留文件拓展名      form.keepExtensions = true;        form.parse(req , function(err , fileds , files){          //圖片的物理路徑,指的是c:node_study……          var pathwuli = files.avatar.path;          //圖片的文件名          var base = path.parse(pathwuli).base;            //查看上傳的文件的寬度、高度          gm(pathwuli).size(function(err, size){              console.log(size.width , size.height);              res.send("<script>window.parent.success_upload_avatar('" + base + "');</script >")          });          });  });

formidable是用來上傳圖片的

gm是用來處理圖片。這裡使用了語法

gm().size(function(err,size){    })

可以得到圖片的尺寸。

後台要給你圖片尺寸,因為你不能耍無賴:讓圖片撐出盒子,又讓圖片被盒子約束。

 

上傳圖片,已經是先上傳圖片,然後在頁面上顯示具有URL伺服器地址的圖片。

然後我們要有一個思維,就是用px來精確控制彈出層的樣子,這樣好看。

 


2.3 圖片的裁切邏輯

 

新瓶裝舊酒,jQueryDOM邏輯還是非常豐富,React在這裡只是一個殼子。

 

  componentDidMount(){          var self = this;          //四個訊號量          var cutX = 0 , cutY = 0, cutW = 100 , cutH = 100;            //cut裡面的貓膩圖片,為了讓cut亮          var $cut_img = $(this.refs.cut_img);            $(this.refs.cut).draggable({              containment : "parent",              drag : function(event , ui){                  cutY = ui.position.top;                  cutX = ui.position.left;                    $cut_img.css({                      "left": -cutX,                      "top": -cutY                  });                    //調用設置預覽圖的函數                  setPreviews();              }          });            //改變尺寸          $(this.refs.cut).resizable({              aspectRatio : 1 ,              containment : "parent",              resize : function(evnet , ui){                  cutW = ui.size.width;                  cutH = ui.size.height;                    //調用設置預覽圖的函數                  setPreviews();              }          });            //設置預覽路          function setPreviews(){              var bigimgW = $(self.refs.bigimg).width();              var bigimgH = $(self.refs.bigimg).height();                //批量設置              $(self.refs.priewBox).find(".pb").each(function(){                  var w = $(this).data("w");                    $(this).find("img").css({                      "width": w * bigimgW / cutW,                      "left": -cutX / cutW * w,                      "top": -cutY / cutH * w                  })              });          }            //裁切按鈕的事件監聽          self.cutBtnHandler = function(){              //圖片原寬和當前寬度的比              var rate = self.props.realw / $(self.refs.bigimg).width();                $.post("/docut" , {                  x: cutX * rate,                  y: cutY * rate,                  w: cutW * rate,                  h: cutH * rate,                  picurl: self.props.tanchucengPicUrl              });          }      }

示例程式碼

 

後端介面

app.post("/docut" , function(req,res){      var form = new formidable.IncomingForm();      form.parse(req, function (err, fileds, files) {          //得到前端發來的各種數據          const {x, y,w,h,picurl} = fileds;          //完整路徑          var fullurl = path.resolve(__dirname , "./www/" + picurl);          //裁切圖片          gm(fullurl)              .crop(w,h,x,y)      //注意這裡的坑:參數的順序是寬、高、x、y。              .resize(180,180)              .write(fullurl , function(err){     //覆蓋原圖即可                  console.log(err)                  console.log("done");              })      });  })

示例程式碼


 

Exit mobile version