Khi nghe đến tiêu đề thì chắc hẳn các bạn không lạ lẫm gì với kỹ thuật AJAX trong Javascript rồi. Nếu như trước đây, các bạn từng biết cách sử dụng kỹ thuật AJAXtrong việc gửi comment, load trang, thêm giỏ hàng..v...v...Và bây giờ các bạn sẽ được làm quen với Kỹ thuật AJAX với Upload và cách các bạn có thể Upload một lúc nhiều File cũng bằng chính kỹ thuật này.
Chắc các bạn cũng đang rất hứng khởi với nó đúng không? Để bắt tay ngay và luôn:
Điều đầu tiên, chúng ta sẽ phải tạo ra một file index.php, không nhất thiết là php vì file này hoàn toàn chúng ta không sử dụng PHP gì trong đó, nếu như bạn có nhu cầu, nội dung file như thế này:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| <!DOCTYPE html> <html> <head> <meta charset= "utf-8" > <meta http-equiv= "X-UA-Compatible" content= "IE=edge" > <title>Mini Upload Tool</title> <link rel= "stylesheet" href= "css/bootstrap.min.css" > <style type= "text/css" > .progress { position: relative; } .progress-text { position: absolute; width: 100%; height: 100%; text-align: right; padding-right: 5px; color: #333; } </style> </head> <body> <img src= "images/progressbar.gif" style= "display:none" /> <div class = "container" > <h1>Mini Upload Tool</h1> <form role= "form" action= "#" method= "post" enctype= "multipart/form-data" onsubmit= "return doUpload();" > <div class = "form-group" > <label for = "myfile" >File Upload</label> <input type= "file" class = "form-control" name= "myfile" id= "myfile" multiple> </div> <input type= "submit" class = "btn btn-default" value= "Upload" /> <input type= "button" class = "btn btn-default" value= "Cancle" onclick= "cancleUpload();" /> </form> <hr> <div id= "progress-group" > <div class = "progress" > <div class = "progress-bar" style= "width: 60%;" > Tên file ở đây </div> <div class = "progress-text" > Tiến trình ở đây </div> </div> <div class = "progress" > <div class = "progress-bar" style= "width: 40%;" > Tên file ở đây </div> <div class = "progress-text" > Tiến trình ở đây </div> </div> </div> </div> <script type= "text/javascript" src= "js/function.js" ></script> </body> </html> |
Trong đó, các cấu trúc mà tôi đã tạo sẵn đã bao gồm thư viện Bootstrap vào trong đó. Bạn có thể tải Bootstrap tạihttp://getbootstrap.com và chép file bootstrap.min.css vào thư mục như cấu trúc của tôi bên trên.
Trong file này, tôi cũng đã customize CSS một số thứ và đã demo ngay khi các bạn mở file này lên.
Các bạn nên lưu ý những thứ sau trong file của tôi:
1. File Input sẽ có id là "myfile"
2. Để Upload nhiều file cùng lúc các bạn không quên đến thuộc tính Multiple trong File Input nhé.
3. Form có sự kiện onsubmit gửi tới hàm doUpload()
4. Button Cancle sẽ có sự kiện onclick gửi tới hàm cancleUpload()
5. Source JS tôi trỏ đến file function.js
6. Vùng div#progress-group do tôi tạo ra để khi chúng ta Upload sẽ tạo ra thêm các vùng chứa các thanh tiến trình tại đây.
7. Cuối cùng là thẻ img tôi chèn ở đầu body, giúp cho việc chúng ta sử dụng AJAX được trơn tru hơn, bằng cách load file hình này vào trước để trình duyệt cache.
Rồi trong file function.js của tôi sẽ như thế này:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
| //Biến toàn cục var http_arr = new Array(); function doUpload() { document.getElementById( 'progress-group' ).innerHTML = '' ; //Reset lại Progress-group var files = document.getElementById( 'myfile' ).files; for (i=0;i<files.length;i++) { uploadFile(files[i], i); } return false ; } function uploadFile(file, index) { var http = new XMLHttpRequest(); http_arr.push(http); /** Khởi tạo vùng tiến trình **/ //Div.Progress-group var ProgressGroup = document.getElementById( 'progress-group' ); //Div.Progress var Progress = document.createElement( 'div' ); Progress.className = 'progress' ; //Div.Progress-bar var ProgressBar = document.createElement( 'div' ); ProgressBar.className = 'progress-bar' ; //Div.Progress-text var ProgressText = document.createElement( 'div' ); ProgressText.className = 'progress-text' ; //Thêm Div.Progress-bar và Div.Progress-text vào Div.Progress Progress.appendChild(ProgressBar); Progress.appendChild(ProgressText); //Thêm Div.Progress và Div.Progress-bar vào Div.Progress-group ProgressGroup.appendChild(Progress); //Biến hỗ trợ tính toán tốc độ var oldLoaded = 0; var oldTime = 0; //Sự kiện bắt tiến trình http.upload.addEventListener( 'progress' , function (event) { if (oldTime == 0) { //Set thời gian trước đó nếu như bằng không. oldTime = event.timeStamp; } //Khởi tạo các biến cần thiết var fileName = file.name; //Tên file var fileLoaded = event.loaded; //Đã load được bao nhiêu var fileTotal = event.total; //Tổng cộng dung lượng cần load var fileProgress = parseInt((fileLoaded/fileTotal)*100) || 0; //Tiến trình xử lý var speed = speedRate(oldTime, event.timeStamp, oldLoaded, event.loaded); //Sử dụng biến ProgressBar.innerHTML = fileName + ' đang được upload...' ; ProgressBar.style.width = fileProgress + '%' ; ProgressText.innerHTML = fileProgress + '% Upload Speed: ' +speed+ 'KB/s' ; //Chờ dữ liệu trả về if (fileProgress == 100) { ProgressBar.style.background = 'url("images/progressbar.gif")' ; } oldTime = event.timeStamp; //Set thời gian sau khi thực hiện xử lý oldLoaded = event.loaded; //Set dữ liệu đã nhận được }, false ); //Bắt đầu Upload var data = new FormData(); data.append( 'filename' , file.name); data.append( 'myfile' , file); http.open( 'POST' , 'upload.php' , true ); http.send(data); //Nhận dữ liệu trả về http.onreadystatechange = function (event) { //Kiểm tra điều kiện if (http.readyState == 4 && http.status == 200) { ProgressBar.style.background = '' ; //Bỏ hình ảnh xử lý try { //Bẫy lỗi JSON var server = JSON.parse(http.responseText); if (server.status) { ProgressBar.className += ' progress-bar-success' ; //Thêm class Success ProgressBar.innerHTML = server.message; //Thông báo } else { ProgressBar.className += ' progress-bar-danger' ; //Thêm class Danger ProgressBar.innerHTML = server.message; //Thông báo } } catch (e) { ProgressBar.className += ' progress-bar-danger' ; //Thêm class Danger ProgressBar.innerHTML = 'Có lỗi xảy ra' ; //Thông báo } } http.removeEventListener( 'progress' ); //Bỏ bắt sự kiện } } function cancleUpload() { for (i=0;i<http_arr.length;i++) { http_arr[i].removeEventListener( 'progress' ); http_arr[i].abort(); } var ProgressBar = document.getElementsByClassName( 'progress-bar' ); for (i=0;i<ProgressBar.length;i++) { ProgressBar[i].className = 'progress progress-bar progress-bar-danger' ; } } function speedRate(oldTime, newTime, oldLoaded, newLoaded) { var timeProcess = newTime - oldTime; //Độ trễ giữa 2 lần gọi sự kiện if (timeProcess != 0) { var currentLoadedPerMilisecond = (newLoaded - oldLoaded)/timeProcess; // Số byte chuyển được 1 Mili giây return parseInt((currentLoadedPerMilisecond * 1000)/1024); //Trả về giá trị tốc độ KB/s } else { return parseInt(newLoaded/1024); //Trả về giá trị tốc độ KB/s } } |
Các bạn nên lưu ý các vấn đề như sau:
1. Javascript phân biệt hoa thường (lỗi này gặp rất nhiều)
2. Biết cách sử dụng JSON và cách bẫy lỗi JSON
3. Sử dụng sự kiện event trả về trong addEventListener, các bạn cũng nên lưu ý đối số cuối cùng trong addEventListener nhé, bạn có thể tham khảo tại đây :
http://www.w3schools.com/js/tryit.asp?filename=tryjs_addeventlistener_usecapture
4. Cuối cùng, tôi nghĩ là khi đến với bài viết này, các bạn cũng đã hiểu qua về Javascript và AJAX cũng ít nhiều rồi. Nếu chưa nắm rõ bạn có thể tham khảo lại bài hướng dẫn của thầy Kenny về khái niệm ajax: Kỹ thuật lập trình ajax kết hợp PHP
Tiếp tục, chúng ta sẽ đến với phần Server-side và ở đây chính là PHP. Các bạn hãy tạo ra file upload.php :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| <?php //Các Mimes quản lý định dạng file $mimes = array ( 'image/jpeg' , 'image/png' , 'image/gif' ); sleep(2); if (isset( $_FILES [ 'myfile' ])) { $fileName = $_FILES [ 'myfile' ][ 'name' ]; $fileType = $_FILES [ 'myfile' ][ 'type' ]; $fileError = $_FILES [ 'myfile' ][ 'error' ]; $fileStatus = array ( 'status' => 0, 'message' => '' ); if ( $fileError == 1) { //Lỗi vượt dung lượng $fileStatus [ 'message' ] = 'Dung lượng quá giới hạn cho phép' ; } elseif (!in_array( $fileType , $mimes )) { //Kiểm tra định dạng file $fileStatus [ 'message' ] = 'Không cho phép định dạng này' ; } else { //Không có lỗi nào move_uploaded_file( $_FILES [ 'myfile' ][ 'tmp_name' ], 'uploads/' . $fileName ); $fileStatus [ 'status' ] = 1; $fileStatus [ 'message' ] = "Bạn đã upload $fileName thành công" ; } echo json_encode( $fileStatus ); exit (); } |
Với file PHP này thật sự không quá khó với dân lập trình không chuyên và thật sự rất dễ với PHP Dev. Tôi nghĩ là trong file này tôi cũng không có giải thích gì nhiều biến $_FILES. Nó chỉ sử dụng cách trả về bằng JSON bằng cáchencode Array mà tôi đã tạo bên trên về đối tượng JSON:
Status : Tình trạng Upload thành công hay chưa?
Message: Thông báo từ phía server gửi về.
Và các bạn lưu ý hơn đó chính là $_FILES['myfile'], như ở trong file function.js, chúng ta đã tạo ra FormData và các khóa Key trong $_FILES được tạo ra từ đó, chứ không phải từ Form mà tôi đã tạo ở index.php và tôi cũng đã cố tình tạo dư ra một khóa "filename" để các bạn có thể tự khám phá khi sử dụng FormData trong Javascript. Chứ nếu mà các bạn chỉ Copy và Paste thì chắc chắn sẽ không chú ý đến chi tiết này vì bên file upload.php tôi có xài cái key filename mà tôi đã tạo ra đâu nào
Sau khi hoàn tất các quá trình trên, còn chờ gì mà không tận hưởng thành quả của chúng ta nào.
Nếu xem qua mà bạn vẫn chưa hiểu, bạn có thể xem phiên bản video để nắm vấn đề rõ hơn nhé:
0 nhận xét:
Đăng nhận xét