從FormData到圖片上傳

FormData對象用以將數據編譯成鍵值對,以便用XMLHttpRequest來發送數據。其主要用於發送表單數據,但亦可用於發送帶鍵數據(keyed data),而獨立於表單使用。若是表單enctype屬性設爲multipart/form-data ,則會使用表單的submit()方法來發送數據,從而,發送數據具備一樣形式。php

以前一直用jquery的form插件自帶的方法ajaxSubmit提交表單。css

$('#myForm2').submit(function() {
   $(this).ajaxSubmit(function() {   
      $('#output2').html("提交成功!歡迎下次再來!").show();    
   });
   return false; //阻止表單默認提交
});
複製代碼

這種方法太依賴庫,在移動端會產生多大的資源消耗,因而仍是用FormData提交比較合適。FormData也是H5新增html

==FormData能夠添加由用戶選擇的HTML 文件類型input,也能夠添加JavaScript file-like 對象== 還能夠直接向FormData對象附加File或Blob類型的文件,以下所示:jquery

data.append("myfile", myBlob, "filename.txt");
複製代碼
1、經過Html元素建立FormData對象
<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>
<form action="">
	<label for="">
		姓名: <input type="text" name="name">
	</label>
	<label for="">
		文件:<input id="file" type="file" name="file">
	</label>
	<label for="">
		<input type="button" value="保存">
	</label>
	<div class="progress"></div>
</form>
<script>
	var btn = document.querySelector('[type=button]');
	var progress = document.querySelector('.progress')
	btn.onclick = function () {
		// 文件元素
		var file = document.querySelector('[type=file]');
		// 經過FormData將文件轉成二進制數據
		var formData = new FormData();
		// 將文件轉二進制
		formData.append('upload', file.files[0]);

		// JavaScript file-like 對象
		var content = '<a id="a"><b id="b">hey!</b></a>'; // 新文件的正文...
		var blob = new Blob([content], { type: "text/xml"});
		formData.append("webmasterfile", blob);

		var xhr = new XMLHttpRequest;
		xhr.open('post', './file.php');
		// 監聽上傳進度
		xhr.upload.onprogress = function (ev) {
			// 事件對象
			// console.log(ev);

			var percent = (ev.loaded / ev.total) * 100 + '%';

			console.log(percent);

			progress.style.width = percent;
		}

		xhr.send(formData);

		xhr.onreadystatechange = function () {
			if(xhr.readyState == 4 && xhr.status == 200) {
				//
			}
		}
	}
</script>
</body>
複製代碼
2、經過Html Form元素建立FormData對象,用ajax提交。
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<form enctype="multipart/form-data" method="post" name="fileinfo">
    <label>Your email address:</label>
    <input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32"
           maxlength="64"/><br/>
    <label>Custom file label:</label>
    <input type="text" name="filelabel" size="12" maxlength="32"/><br/>
    <label>File to stash:</label>
    <input type="file" name="file" required/>
    <input type="submit" value="Stash the file!"/>
</form>
<script src="//cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
<script>
    var form = document.forms.namedItem("fileinfo");
    form.addEventListener('submit', function (ev) {
        ev.preventDefault()
        // 文件元素
        var fd = new FormData(document.querySelector("form"));
        fd.append("CustomField", "This is some extra data");
        $.ajax({
            url: "./file.php",
            type: "POST",
            data: fd,
            processData: false,  // 不處理數據
            contentType: false   // 不設置內容類型
        });
    })
</script>
</body>
複製代碼

請求頭爲:Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryVXQzCH5gOtjud1Xuweb

「——WebKitFormBoundary」加16位隨機Base64位編碼的字符串做爲分隔邊界ajax

3、使用antd-mobile的ImagePicker + fetch上傳
import { ImagePicker, WingBlank, SegmentedControl } from 'antd-mobile';
const data = [{
  url: 'https://zos.alipayobjects.com/rmsportal/PZUUCKTRIHWiZSY.jpeg',
  id: '2121',
}, {
  url: 'https://zos.alipayobjects.com/rmsportal/hqQWgTXdrlmVVYi.jpeg',
  id: '2122',
}];

export default class ImagePickerExample extends React.Component {
  state = {
    files: data,
    multiple: false,
  }
  onImageChange = (files, type, index) => {
    if (type == 'add') {
      var file = files[files.length - 1].file

      let formData = new FormData();
      formData.append("file", file);

      files[files.length - 1].url = '../../../../src/white.png'
      this.setState({files})

      fetch('./file.php', {
        method: 'POST',
        headers: {},
        body: formData,
      }).then((response) => response.json()).then((res)=> {
          if (res.code == 200) {
            files[files.length - 1].url = res.value.fileUrl
          }
          this.setState({files},function () {
            const dom = document.querySelectorAll('.am-image-picker-item')
            dom[files.length - 1].className +=' now'
          });
      }).catch((err)=> {
        util.showWarning(err)
      });
    } else {
      this.setState({files});
    }
  }
  render() {
    const { files } = this.state;
    return (
      <div>
        <ImagePicker
          files={files}
          onChange={this.onImageChange}
          onImageClick={(index, fs) => console.log(index, fs)}
          selectable={files.length < 3}
          multiple={false}
        />
      </div>
    );
  }
}
複製代碼

onImageChange files 值發生變化觸發的回調函數, operationType 操做類型有添加,移除,若是是移除操做,則第三個參數表明的是移除圖片的索引json

判斷type== 'add'時就上傳圖片,由於設置的是單個上傳,因此files數組最後一個數據就是新添加須要上傳的filesegmentfault

var file = files[files.length - 1].file
複製代碼

使用FormData將數據封裝數組

let formData = new FormData();
formData.append("file", file);
複製代碼

由於上傳須要時間,爲了加強用戶體驗,先將地址替換成一張透明png圖片展位,顯示loadingbash

files[files.length - 1].url = '../../../../src/white.png'
  this.setState({files})
複製代碼

注意在使用fetch方法時,不用設置header,body上直接傳封裝後的formData

fetch('./file.php', {
    method: 'POST',
    headers: {},
    body: formData,
  })
複製代碼

原生的移動端上傳參考大神的方法: segmentfault.com/a/119000001…

相關文章
相關標籤/搜索