HƯỚNG DẪN UPLOAD FILE BẰNG AJAX KẾT HỢP VỚI PROGRESS BAR


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.
Hướng dẫn Upload File bằng AJAX kết hợp với Progress Bar

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é:


Share on Google Plus

About Unknown

This is a short description in the author block about the author. You edit it by entering text in the "Biographical Info" field in the user admin panel.
    Blogger Comment
    Facebook Comment

0 nhận xét:

Đăng nhận xét