現代瀏覽器支援 `FormData` + `XMLHttpRequest Level 2` 實現無刷新檔案上傳,支援進度條、多檔、二進位傳輸。本文提供極簡後端接收與前端上傳邏輯,無第三方依賴。
upload.php<?php
if (isset($_FILES["myfile"])) {
$ret = [];
$uploadDir = 'images' . DIRECTORY_SEPARATOR . date("Ymd") . DIRECTORY_SEPARATOR;
$dir = __DIR__ . DIRECTORY_SEPARATOR . $uploadDir;
// 遞迴建立目錄並設權限
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
chmod($dir, 0777);
}
if (!is_array($_FILES["myfile"]["name"])) {
// 單檔上傳
$ext = pathinfo($_FILES["myfile"]["name"], PATHINFO_EXTENSION);
$fileName = time() . uniqid() . '.' . $ext;
move_uploaded_file($_FILES["myfile"]["tmp_name"], $dir . $fileName);
$ret['file'] = DIRECTORY_SEPARATOR . $uploadDir . $fileName;
}
// 多檔支援可在此擴充
header('Content-Type: application/json');
echo json_encode($ret);
}
?>
index.html<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Ajax 檔案上傳</title>
<style>
.txt { height:28px; border:1px solid #cdcdcd; width:670px; }
.mybtn { background:#fff; line-height:14px; vertical-align:middle; border:1px solid #cdcdcd; height:30px; width:70px; }
.file { position:absolute; top:0; right:80px; height:24px; opacity:0; filter:alpha(opacity:0); width:260px; }
</style>
</head>
<body>
<div class="form-group">
<label>圖片</label><br/>
<input type="text" name="textfield" id="textfield" class="txt" readonly />
<span onclick="file.click()" class="mybtn">瀏覽...</span>
<input type="file" name="file" class="file" id="file" size="28"
onchange="document.getElementById('textfield').value=this.value" />
<span onclick="UpladFile()" class="mybtn">上傳</span>
</div>
<script>
var xhr;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} else if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
}
function UpladFile() {
var fileObj = document.getElementById("file").files[0];
if (!fileObj) { alert("請選擇檔案"); return; }
var form = new FormData();
form.append("myfile", fileObj);
createXMLHttpRequest();
xhr.onreadystatechange = handleStateChange;
xhr.open("post", "upload.php", true);
xhr.send(form);
}
function handleStateChange() {
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 0) {
var result = xhr.responseText;
var json = eval("(" + result + ")"); // 或 JSON.parse(result)
alert('圖片連結:\n' + json.file);
}
}
}
</script>
</body>
</html>
| 技術 | 說明 |
|---|---|
| FormData | 自動構建 multipart/form-data 體,支援檔案、欄位混合 |
| XMLHttpRequest Level 2 | 支援 `upload.onprogress` 事件,可做進度條 |
| input[type=file] 隱藏 | opacity:0 覆蓋在自訂按鈕上,美化 UI |
| JSON 回應 | 結構化回傳路徑、錯誤碼、訊息,前端易處理 |
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percent = Math.round((e.loaded / e.total) * 100);
document.getElementById('progress').style.width = percent + '%';
}
};
原生實作理解核心原理,專案開發建議站在巨人肩膀上。