การใช้งาน ajax สร้าง Drag and Drop เพื่ออัพโหลดไฟล์ อย่างง่าย

เขียนเมื่อ 1 ปีก่อน โดย Ninenik Narkdee
ajax draganddrop fetch

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ ajax draganddrop fetch

ดูแล้ว 1,380 ครั้ง


เนื้อหานี้จะพามาดูแนวทางการสร้างวิธีการลากไฟล์มาวางในพื้นที่ที่กำหนดแล้วให้ทำการ
อัพโหลดไฟล์นั้นๆ หรือที่เรียกว่าการอัพโหลดไฟล์แบบ drag and drop โดยคำสั่งเกี่ยวกับ
การจัดการวิธีการอัพโหลด เราจะใช้ javascript และในส่วนของคำสั่งทำการอัพโหลดไฟล์ฝั่ง
server เราจะใช้เป็นฟังก์ชั่น php อย่างเเกี่ยวกับการอัพโหลดไฟล์อย่างง่าย
 
1. สร้างส่วนของการกำหนดพื้นที่ของตำแหน่งที่เราจะให้สามารถลากไฟล์มาวาง
 
<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
</style>
<div class="drop-place">
    <span class="drop-guide">ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
</div>
 
2. กำหนดส่วนของ javascript ในการทำงานเมื่อมีการลากไฟล์เข้ามาในพื้นที่ เบื้องต้นจะให้เห็น
รูปแบบการทำงานของเหตุการณ์ต่างๆ ที่จะเกิดขึ้นสำหรับการลากไฟล์มาในพื้นที่เพื่ออัพโหลด
 
<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
        console.log("DragEnter");
        drop_guide.textContent = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
        console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
        console.log("DragLeave");
        drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.textContent = 'กำลังอัพโหลดไฟล์...';
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
    });
});
</script>
 
3. โฟกัสในส่วนของการ drop ไฟล์ 
 
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.textContent = 'กำลังอัพโหลดไฟล์...';
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        console.log(image);
    });
 
เมื่อมีการวางไฟล์เพื่อทำการอัพโหลด เราสามารถดูข้อมูล FileList ที่นำมาวาง ผ่านค่า
event.dataTransfer.files ซึ่งจะเป็นข้อมูลไฟล์อาเรย์ นั่นหมายความว่า เราสามารถลาก
มาวางทีละหลายๆ ไฟล์พร้อมกันได้ แต่ในตัวอย่างนี้เราจะอัพโหลดแค่ไฟล์เดียวก่อน
 
เมื่อเราได้ข้อมูลไฟล์รูปที่จะอัพโหลด ต่อไป เราต้องทำการสร้างฟอร์มข้อมูล ในที่นี้ก็คือ 
ข้อมูล FormData object โดยสร้าง ตัวแปร สำหรับเก็บข้อมูลดังนี้
 
var formData = new FormData();
 
ถ้าเรานึกภาพไม่ออกว่าข้อมูล FormData คืออะไร ให้เรานึกถึงรูปแบบฟอร์มส่งข้อมูลทั่วไป
 
<form action="" method="post">
<input type="text">
<button type="submit">Send</button>
</form>
 
ข้างต้นคือรูปแบบฟอร์มที่สร้างด้วย html แต่การสร้างด้วย javascript จะใช้เป็น new FormData();
ซึ่งจะเป็นการสร้างแค่ฟอร์มข้อมูล ยังไม่มี Element หรือฟิลด์ข้อมูลใดๆ เช่นตัวอย่างด้านบน จะมี input
text เป็นองค์ประกอบ ดังนั้น คำสั่งที่จะเพิ่มองค์ประกอบ หรือ Element ของฟอร์มจะใช้เป็น
 
var formData = new FormData();
formData.append('picture', image[0]);
 
เรากำหนดชื่อฟิลด์เป็น picture เนื่องจากข้อมูลจากตัวแปร image ของเราเป็นอาเรย์รูปภาพ 
ตัวแปรข้อมูลที่ส่งไปก็จะเป็น $_FILES['picture'] และเมื่อเรา จะเลือกเพียงไฟล์เดียว จึงกำหนดเป็นค่า
ที่อาเรย์ 0 หรือค่าแรก เป็น image[0] เป็นค่ารุปภาพที่เรากำหนดให้ตัวแปร $_FILES['picture']
 
4. เมื่อเราได้ข้อมูลฟอร์มสำหรับส่งเรียบร้อยแล้ว ต่อไปก็คือการสร้างฟังก์ชั่น ajax สำหรับการส่งข้อมูล
ในที่นี้เราจะใช้คำสั่ง fetch() ซึ่งคำสั่งนี้เป็นคำสั่งที่มีเรื่องของเวลาที่ต้องรอเข้ามาเกี่ยวข้อง เพราะเป็น
การส่งข้อมูลไปยัง server และต้องรอการทำงาน หรือก็คือการทำงานแบบ async (asynchronous)
 
    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        const response_async =  await fetch('upload.php?upload', {
            method: "POST",  
            body: formData // ส่งข้อมูลฟอร์ม
        });
        // เพื่อให้ข้อมูลที่ส่งกลับมา สามารถนำไปประยุกต์ใช้ได้ เราจึงให้ส่งเป็น json object
        return response_async.json();
    }   
 
5. เรียกใช้ฟังก์ชั่น ajax สำหรับอัพโหลดหรือส่งข้อมูลไปยัง server เมื่อเราได้ฟังก์ชั่นสำหรับส่งข้อมูล
แล้ว ในการเรียกใช้ฟังก์ชั่น async ก็จะต้องรอข้อมูลส่งกลับมาก่อนถึงจะนำไปประมวลผลหรือทำงานต่อ
ดังนั้นวิธีการใช้งานจะเป็นในรูปแบบดังนี้
 
    uploadFormData(formData) // ส่งข้อมูลไปัยัง server
    .then( response => { // เมื่อส่งข้อมูลกลับมา
        console.log( response ); // JSON data 
        if(response.status=="OK"){
            event.target.classList.remove('dropped');
            drop_guide.classList.remove('process');
            drop_guide.classList.add('success');
            drop_guide.textContent = 'อัพโหลดไฟล์เรียบร้อยแล้ว';
            setTimeout(()=>{
                drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                drop_guide.classList.remove('success');
            },2000);
        }
    });
 
6. ส่วนของไฟล์สำหรับอัพโหลดในฝั่งของ server อย่างง่าย สามารถประยุกต์เพิ่มเติมได้ตามต้องการ
ไฟล์ upload.php
 
<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {
    if (is_uploaded_file($_FILES['picture']['tmp_name'])) {
        $sourcePath = $_FILES['picture']['tmp_name'];
        $targetPath = "uploads/" . $_FILES['picture']['name'];
        if (move_uploaded_file($sourcePath, $targetPath)) {
            $response = array(
                "status"=>"OK"
            );  
        }else{
            $response = array(
                "status"=>"Fail"
            );            
        }
    }else{
        $response = array(
            "status"=>"Fail"
        );
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
ตัวอย่างไฟล์ทดสอบ ajax_draganddrop.php ทั้งหมด
<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {
    if (is_uploaded_file($_FILES['picture']['tmp_name'])) {
        $sourcePath = $_FILES['picture']['tmp_name'];
        $targetPath = "uploads/" . $_FILES['picture']['name'];
        if (move_uploaded_file($sourcePath, $targetPath)) {
            $response = array(
                "status"=>"OK"
            );  
        }else{
            $response = array(
                "status"=>"Fail"
            );            
        }
    }else{
        $response = array(
            "status"=>"Fail"
        );
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
</style>
<div class="drop-place">
    <span class="drop-guide">ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
</div>

<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.textContent = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.textContent = 'กำลังอัพโหลดไฟล์...';
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        var formData = new FormData();
        console.log(image);
        formData.append('picture', image[0]);

    uploadFormData(formData) // ส่งข้อมูลไปัยัง server
    .then( response => { // เมื่อส่งข้อมูลกลับมา
        console.log( response ); // JSON data 
        if(response.status=="OK"){
            event.target.classList.remove('dropped');
            drop_guide.classList.remove('process');
            drop_guide.classList.add('success');
            drop_guide.textContent = 'อัพโหลดไฟล์เรียบร้อยแล้ว';
            setTimeout(()=>{
                drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                drop_guide.classList.remove('success');
            },2000);
        }
    });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        const response_async =  await fetch('ajax_draganddrop.php?upload', {
            method: "POST",  
            body: formData // ส่งข้อมูลฟอร์ม
        });
        // เพื่อให้ข้อมูลที่ส่งกลับมา สามารถนำไปประยุกต์ใช้ได้ เราจึงให้ส่งเป็น json object
        return response_async.json();
    }    

});
</script>
    
</body>
</html>


   เพิ่มเติมเนื้อหา ครั้งที่ 1 วันที่ 18-02-2024


การตรวจสอบข้อผิดพลาดกรณีใช้งาน คำสั่ง fetch() ในการส่งข้อมูล

 
ในส่วนนี้จะมาเพิ่มในส่วนของการตรวจสอบเพิ่มเติมกรณีเกิดข้อผิดพลาดระหว่างการ
ส่งข้อมูลด้วยคำสั่ง fetch() เช่น ชื่อไฟล์ไม่ถูกต้อง หรือ ไม่พบไฟล์ หรือกรณี server 
มีปัญหาไม่ตอบสนอง ทั้งหมดนี้ รูปแบบก่อนหน้าจะไม่ได้กำหนดการตรวจสอบไว้

<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.textContent = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.textContent = 'กำลังอัพโหลดไฟล์...';
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        var formData = new FormData();
        console.log(image);
        formData.append('picture', image[0]);

        uploadFormData(formData) // ส่งข้อมูลไปัยัง server
        .then( response => { // เมื่อส่งข้อมูลกลับมา
            console.log( response ); // JSON data 
            if(response.status=="OK"){
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');
                drop_guide.classList.add('success');
                drop_guide.textContent = 'อัพโหลดไฟล์เรียบร้อยแล้ว';
                setTimeout(()=>{
                    drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);
            }else{
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');            
                drop_guide.textContent = response.text;
                setTimeout(()=>{
                    drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);            
            }
        });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        try{
            const response_async =  await fetch('ajax_draganddrop.php?upload', {
                method: "POST",  
                body: formData // ส่งข้อมูลฟอร์ม
            });
            // ต้อง(ไม่)เป็น 404 หรือ 500 คือ ไต้ไม่เป็น ไม่พบไฟล์ หรือ server ไม่ตอบสนอง
            if(![404,500].includes(response_async.status)){
                return response_async.json();
            }else{ // กรณี ไม่พบไฟล์ 
                var errors = {status:'Fail',text:'เกิดข้อผิดพลาดลองใหม่อีกครั้ง'};
                return errors;
            }
        }catch (error) { // ส่วนใหญ่เป็นกรณี 500 หรือ server ไม่ตอบสนอง
            console.error(error);
            var errors = {status:'Fail',text:'การเชื่อมต่อ server ไม่ตอบสนอง'};
            return errors;
        }
    }    

});
</script>


   เพิ่มเติมเนื้อหา ครั้งที่ 2 วันที่ 18-02-2024


การอัพโหลดทีละหลายๆไฟล์ หรือลากทีละหลายไฟล์มาวาง

 
ก่อนหน้าเราให้ตัวอย่างการอัพโหลดโดยเลือกไฟล์เดียว นั่นคือ รูปแบบเดิม ถึงเราจะเลือกไฟล์
หลายไฟล์มาวาง แต่ก็จะทำการส่งเฉพาะไฟล์แรกไฟล์เดียวเท่านั้นไปอัพโหลด โดยส่งข้อมูลไป
 
formData.append('picture', image[0]);
 
เราใช้ชื่อฟิลด์เป็น picture และเลือกรูปแบบกำหนดเจาะจงให้เป็นรูปแรกด้วยค่า 0 เป็น key
ของอาเรย์รูปที่มาวาง แต่เมื่อเราจะทำการส่งไปทีละหลายๆไฟล์ เราก็จะทำการเปลี่ยนชื่อฟิลด์ให้
เป็นแบบอาเรย์ แล้วทำการวนลูปเพิ่มฟิลด์เข้าไปใน formData ดังนี้
 
for (var i = 0; i < image.length; i++) {
    formData.append('picture[]', image[i]);
}
 
จากนั้นก็ปรับแต่งข้อความตามต้องการเช่น การแจ้งว่ากำลังอัดโหลด (จำนวน) ไฟล์..
 
drop_guide.textContent = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
 
หรือเมื่ออัพโหลดเรียบร้อยแล้วก็กำหนดเป็น อัพโหลด (จำนวน)/(ทั้งหมด) ไฟล์ เรียบร้อยแล้ว
 
drop_guide.textContent = 'อัพโหลด '+response.num_success+'/'+
                        response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
 
และอีกส่วนที่ต้องแก้ไขคือส่วนของฝั่ง server เนื่องจากชื่อฟิลด์มีการแก้ไขให้ส่งแบบ array
ดังนั้นการทำงานก็จะปรับเล็กน้อยเป็นดังนี้
 
<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {    
    if(is_array($_FILES['picture']['name'])){
        $num_success = 0; // จำนวนอัพโหลดสำเร็จ
        $num_upload = count($_FILES['picture']['name']); // จำนวนไฟล์ทั้งหมด

        for($i = 0; $i < $num_upload; $i++){
            if (is_uploaded_file($_FILES['picture']['tmp_name'][$i])) {
                $sourcePath = $_FILES['picture']['tmp_name'][$i];
                $targetPath = "uploads/" . $_FILES['picture']['name'][$i];
                if (move_uploaded_file($sourcePath, $targetPath)) {
                    $num_success++; 
                }
            }
        }
        $response = array(
            "status"=>"OK",
            "num_success"=>$num_success,
            "num_upload"=>$num_upload
        );  
    }else{
        $response = array(
            "status"=>"Fail"
        );    
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
 
โค้ดไฟล์ตัวอย่างทั้งหมด ajax_draganddrop.php
 
<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {    
    if(is_array($_FILES['picture']['name'])){
        $num_success = 0; // จำนวนอัพโหลดสำเร็จ
        $num_upload = count($_FILES['picture']['name']); // จำนวนไฟล์ทั้งหมด

        for($i = 0; $i < $num_upload; $i++){
            if (is_uploaded_file($_FILES['picture']['tmp_name'][$i])) {
                $sourcePath = $_FILES['picture']['tmp_name'][$i];
                $targetPath = "uploads/" . $_FILES['picture']['name'][$i];
                if (move_uploaded_file($sourcePath, $targetPath)) {
                    $num_success++; 
                }
            }
        }
        $response = array(
            "status"=>"OK",
            "num_success"=>$num_success,
            "num_upload"=>$num_upload
        );  
    }else{
        $response = array(
            "status"=>"Fail"
        );    
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
</style>
<div class="drop-place">
    <span class="drop-guide">ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
</div>

<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.textContent = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        drop_guide.textContent = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
        var formData = new FormData();
        console.log(image);
        // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
        for (var i = 0; i < image.length; i++) {
            formData.append('picture[]', image[i]);
        }
        //formData.append('picture', image[0]);

        uploadFormData(formData) // ส่งข้อมูลไปัยัง server
        .then( response => { // เมื่อส่งข้อมูลกลับมา
            console.log( response ); // JSON data 
            if(response.status=="OK"){
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');
                drop_guide.classList.add('success');
                drop_guide.textContent = 'อัพโหลด '+response.num_success+'/'+
                                        response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                setTimeout(()=>{
                    drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);
            }else{
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');            
                drop_guide.textContent = response.text;
                setTimeout(()=>{
                    drop_guide.textContent = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);            
            }
        });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        try{
            const response_async =  await fetch('ajax_draganddrop.php?upload', {
                method: "POST",  
                body: formData // ส่งข้อมูลฟอร์ม
            });
            // ต้อง(ไม่)เป็น 404 หรือ 500 คือ ไต้ไม่เป็น ไม่พบไฟล์ หรือ server ไม่ตอบสนอง
            if(![404,500].includes(response_async.status)){
                return response_async.json();
            }else{ // กรณี ไม่พบไฟล์ 
                var errors = {status:'Fail',text:'เกิดข้อผิดพลาดลองใหม่อีกครั้ง'};
                return errors;
            }
        }catch (error) { // ส่วนใหญ่เป็นกรณี 500 หรือ server ไม่ตอบสนอง
            console.error(error);
            var errors = {status:'Fail',text:'การเชื่อมต่อ server ไม่ตอบสนอง'};
            return errors;
        }
    }    

});
</script>
    
</body>
</html>


   เพิ่มเติมเนื้อหา ครั้งที่ 3 วันที่ 18-02-2024


การกำหนดให้รองรับทั้งการเลือก browse ไฟล์ และลากไฟล์มาวางเพื่ออัพโหลด

 
เนื้อหาเพิ่มเติมนี้จะทำการเพิ่มเติมความสามารถให้เราเลือกได้ว่า จะลากไฟล์มาวางเพื่อ
อัพโหลดหรือเลือกไฟล์ที่ตำแหน่งที่ต้องการ เพราะบางครั้ง เราก็อาจจะไม่ได้เปิดหน้าไฟล์
ที่จะลากมาวางไว้ ก็ให้สามารถเลือกไฟล์โดยตรงได้ ซึ่งรองรับการเลือกหลายๆ ไฟล์พร้อมกัน
 
วิธีการคือ เราจะมีปุ่มข้อความ สำหรับให้เลือกไฟล์ เมื่อคลิกเลือก ก็จะทำการสร้าง input file
ขึ้นมาเพื่อใช้สำหรับรับไฟล์ที่เลือก โดยเราจะใช้วิธีการซ่อนไว้ เพื่อให้ไม่ต้องเห็น input นั้น
โดยกำหนด div ไว้ซ่อน
 
<style>
.hidden-inputfile{
    width: 1px;
    height: 1px;
    visibility: hidden;
}
</style>
<div class="hidden-inputfile"></div>
 
จากนั้นเมื่อเราทำการคลิกปุ่ม เลือกไฟล์ ก็จะทำการตรวจสอบว่า input file อยู่ก่อนแล้วไหม 
ถ้ายังไม่มีก็ให้ทำการสร้างขึ้นมา จากนั้นให้เกิด event click ขึ้นเพื่อเรืยกหน้าต่างเลือกไฟล์
ขี้นมา หลักจากเลือกไฟล์ ก็นำรายการไฟล์ที่เลือก เข้าไปสู่ขั้นตอนการอัพโหลดไฟล์ ที่ใช้ร่วมกัน
กับแบบของการลากวาง
 
ไฟล์ตัวอย่างทั้งหมด ajax_draganddrop.php 

<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {    
    if(is_array($_FILES['picture']['name'])){
        $num_success = 0; // จำนวนอัพโหลดสำเร็จ
        $num_upload = count($_FILES['picture']['name']); // จำนวนไฟล์ทั้งหมด

        for($i = 0; $i < $num_upload; $i++){
            if (is_uploaded_file($_FILES['picture']['tmp_name'][$i])) {
                $sourcePath = $_FILES['picture']['tmp_name'][$i];
                $targetPath = "uploads/" . $_FILES['picture']['name'][$i];
                if (move_uploaded_file($sourcePath, $targetPath)) {
                    $num_success++; 
                }
            }
        }
        $response = array(
            "status"=>"OK",
            "num_success"=>$num_success,
            "num_upload"=>$num_upload
        );  
    }else{
        $response = array(
            "status"=>"Fail"
        );    
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
.hidden-inputfile{
    width: 1px;
    height: 1px;
    visibility: hidden;
}
</style>
<div class="drop-place">
    <span class="drop-guide"><a href="#" class="choose-image">เลือกไฟล์</a> หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
</div>
<div class="hidden-inputfile"></div>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.innerHTML = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.innerHTML = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
        var formData = new FormData();
        console.log(image);
        // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
        for (var i = 0; i < image.length; i++) {
            formData.append('picture[]', image[i]);
        }
        //formData.append('picture', image[0]);

        uploadFormData(formData) // ส่งข้อมูลไปัยัง server
        .then( response => { // เมื่อส่งข้อมูลกลับมา
            console.log( response ); // JSON data 
            if(response.status=="OK"){
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');
                drop_guide.classList.add('success');
                drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                        response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);
            }else{
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');            
                drop_guide.innerHTML = response.text;
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                },3000);            
            }
        });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        try{
            const response_async =  await fetch('ajax_draganddrop.php?upload', {
                method: "POST",  
                body: formData // ส่งข้อมูลฟอร์ม
            });
            // ต้อง(ไม่)เป็น 404 หรือ 500 คือ ไต้ไม่เป็น ไม่พบไฟล์ หรือ server ไม่ตอบสนอง
            if(![404,500].includes(response_async.status)){
                return response_async.json();
            }else{ // กรณี ไม่พบไฟล์ 
                var errors = {status:'Fail',text:'เกิดข้อผิดพลาดลองใหม่อีกครั้ง'};
                return errors;
            }
        }catch (error) { // ส่วนใหญ่เป็นกรณี 500 หรือ server ไม่ตอบสนอง
            console.error(error);
            var errors = {status:'Fail',text:'การเชื่อมต่อ server ไม่ตอบสนอง'};
            return errors;
        }
    }   

    // กำหนด event ให้กับปุ่ม เลือกไฟล์ สังเกตว่า เราไม่ได้กำหนดให้กับปุ่มโดยตรง
    // แต่กำหนดในกับ drop-place แทน แล้วค่อยไปตรวจสอบว่า ถ้าตัวที่คลิกเป็นปุ่ม
    // choose-image หรือไม่ ถ้าใช่ ให้ทำงาน ทั้งนี้ก็เพราะว่า ถ้าเรากำหนดโดยตรง
    // ปุ่มที่ถูกสร้างมาจาก javascript จะไม่ทำงาน วิธีนี้จึงเป็นการป้องกันปัญหานั้น
    el.addEventListener("click", (event) => {
        var chooseEl = event.target.closest('.choose-image');
        if (chooseEl) { // คลิกโดยปุ่ม เลือกไฟล์หรือไม่
            createUploadFileInput();
        }
        event.preventDefault();
    });

    // ฟังก์ชั่นสำหรับสร้าง input file ให้เลือก พร้อมให้รองรับการอัพโหลดไฟล์ เมื่อเลือกไฟล์
    function createUploadFileInput() {

        var fileInputDOM = document.querySelector('.image_upload');
        var placeForFileInput = document.querySelector('.hidden-inputfile');

        // ตรวจสอบว่า ถ้ายังไม่มี ให้ทำการสร้างขึ้นมาก่อน
        if (!fileInputDOM) {

            // ทำการสร้าง
            var fileInput = document.createElement('input');

            fileInput.type = 'file';
            fileInput.name = 'picture[]'
            fileInput.classList.add('image_upload');
            fileInput.multiple = true;
            fileInput.accept = 'image/*';
            placeForFileInput.appendChild(fileInput);

            // เมื่อมีการเลือกไฟล์ หรือเปลี่ยนแปลงการเลือกไฟล์
            fileInput.addEventListener("change", (event) => {
                event.preventDefault();
                console.log("choose file");
                var image = fileInput.files; // เก็บตัวแปรไฟล์ที่เลือก
                if(image.length>0){ // ถ้ามีการเลือกไฟล์ 
                    drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
                    var formData = new FormData();
                    console.log(image);
                    // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
                    for (var i = 0; i < image.length; i++) {
                        formData.append('picture[]', image[i]);
                    }
                    //formData.append('picture', image[0]);

                    uploadFormData(formData) // ส่งข้อมูลไปัยัง server
                    .then( response => { // เมื่อส่งข้อมูลกลับมา
                        console.log( response ); // JSON data 
                        if(response.status=="OK"){
                            drop_guide.classList.remove('process');
                            drop_guide.classList.add('success');
                            drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                                    response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                            },3000);
                        }else{
                            drop_guide.classList.remove('process');            
                            drop_guide.innerHTML = response.text;
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                            },3000);            
                        }
                    });


                }

            });   
            fileInput.click(); // ให้ input file ถูกคลิก หลังจากสร้าง        
        }else{
            fileInputDOM.click(); // ให้ input file ถูกคลิก ตัวที่ถูกสร้างแล้ว
        }

    }    
    

});
</script>
    
</body>
</html>


 


   เพิ่มเติมเนื้อหา ครั้งที่ 4 วันที่ 18-02-2024


กำหนดให้แสดงรูปตัวอย่างไฟล์ที่กำลังอัพโหลด

 
เนื้อหาเพิ่มเติมนี้ เราจะเพิ่มในส่วนของฟังก์ชั่น ให้แสดงรูปตัวอย่าง เพื่อให้เห็นชัดเจนว่า
เราได้ทำการเลือกไฟล์ที่จะอัพโหลดถูกต้องหรือไม่ เป็นการช่วยตรวจสอบเพิ่มเติมอีกที
แนวทางการปรับโค้ด แค่เพิ่มส่วนของฟังก์ชั่น และการแสดงเข้ามา รายละเอียดอยู่ในโค้ด
ตัวอย่างทั้งหมดด้านล่างนี้
 
ไฟล์โค้ดตัวอย่าง ajax_draganddrop.php

<?php
if(isset($_GET['upload'])){

if (!empty($_FILES['picture'])) {    
    if(is_array($_FILES['picture']['name'])){
        $num_success = 0; // จำนวนอัพโหลดสำเร็จ
        $num_upload = count($_FILES['picture']['name']); // จำนวนไฟล์ทั้งหมด

        for($i = 0; $i < $num_upload; $i++){
            if (is_uploaded_file($_FILES['picture']['tmp_name'][$i])) {
                $sourcePath = $_FILES['picture']['tmp_name'][$i];
                $targetPath = "uploads/" . $_FILES['picture']['name'][$i];
                if (move_uploaded_file($sourcePath, $targetPath)) {
                    $num_success++; 
                }
            }
        }
        $response = array(
            "status"=>"OK",
            "num_success"=>$num_success,
            "num_upload"=>$num_upload
        );  
    }else{
        $response = array(
            "status"=>"Fail"
        );    
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);		
exit; 
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
.hidden-inputfile{
    width: 1px;
    height: 1px;
    visibility: hidden;
}
#thumbnail,div.removepic{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}
#thumbnail img{
    width:50px;
    height:50px;
    margin:5px;
}
canvas{
    border:1px solid red;
}    
</style>
<div class="drop-place">
    <span class="drop-guide"><a href="#" class="choose-image">เลือกไฟล์</a> หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
    <div id="thumbnail"></div>
</div>
<div class="hidden-inputfile"></div>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    const thumbnail = document.querySelector("#thumbnail");    
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.innerHTML = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.innerHTML = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        showThumbnail(image);
        drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
        var formData = new FormData();
        console.log(image);
        // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
        for (var i = 0; i < image.length; i++) {
            formData.append('picture[]', image[i]);
        }
        //formData.append('picture', image[0]);

        uploadFormData(formData) // ส่งข้อมูลไปัยัง server
        .then( response => { // เมื่อส่งข้อมูลกลับมา
            console.log( response ); // JSON data 
            if(response.status=="OK"){
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');
                drop_guide.classList.add('success');
                drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                        response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                    thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                },3000);
            }else{
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');            
                drop_guide.innerHTML = response.text;
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                    thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                },3000);            
            }
        });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        try{
            const response_async =  await fetch('ajax_draganddrop.php?upload', {
                method: "POST",  
                body: formData // ส่งข้อมูลฟอร์ม
            });
            // ต้อง(ไม่)เป็น 404 หรือ 500 คือ ไต้ไม่เป็น ไม่พบไฟล์ หรือ server ไม่ตอบสนอง
            if(![404,500].includes(response_async.status)){
                return response_async.json();
            }else{ // กรณี ไม่พบไฟล์ 
                var errors = {status:'Fail',text:'เกิดข้อผิดพลาดลองใหม่อีกครั้ง'};
                return errors;
            }
        }catch (error) { // ส่วนใหญ่เป็นกรณี 500 หรือ server ไม่ตอบสนอง
            console.error(error);
            var errors = {status:'Fail',text:'การเชื่อมต่อ server ไม่ตอบสนอง'};
            return errors;
        }
    }   

    // กำหนด event ให้กับปุ่ม เลือกไฟล์ สังเกตว่า เราไม่ได้กำหนดให้กับปุ่มโดยตรง
    // แต่กำหนดในกับ drop-place แทน แล้วค่อยไปตรวจสอบว่า ถ้าตัวที่คลิกเป็นปุ่ม
    // choose-image หรือไม่ ถ้าใช่ ให้ทำงาน ทั้งนี้ก็เพราะว่า ถ้าเรากำหนดโดยตรง
    // ปุ่มที่ถูกสร้างมาจาก javascript จะไม่ทำงาน วิธีนี้จึงเป็นการป้องกันปัญหานั้น
    el.addEventListener("click", (event) => {
        var chooseEl = event.target.closest('.choose-image');
        if (chooseEl) { // คลิกโดยปุ่ม เลือกไฟล์หรือไม่
            createUploadFileInput();
        }
        event.preventDefault();
    });

    // ฟังก์ชั่นสำหรับสร้าง input file ให้เลือก พร้อมให้รองรับการอัพโหลดไฟล์ เมื่อเลือกไฟล์
    function createUploadFileInput() {

        var fileInputDOM = document.querySelector('.image_upload');
        var placeForFileInput = document.querySelector('.hidden-inputfile');

        // ตรวจสอบว่า ถ้ายังไม่มี ให้ทำการสร้างขึ้นมาก่อน
        if (!fileInputDOM) {

            // ทำการสร้าง
            var fileInput = document.createElement('input');

            fileInput.type = 'file';
            fileInput.name = 'picture[]'
            fileInput.classList.add('image_upload');
            fileInput.multiple = true;
            fileInput.accept = 'image/*';
            placeForFileInput.appendChild(fileInput);

            // เมื่อมีการเลือกไฟล์ หรือเปลี่ยนแปลงการเลือกไฟล์
            fileInput.addEventListener("change", (event) => {
                event.preventDefault();
                console.log("choose file");
                var image = fileInput.files; // เก็บตัวแปรไฟล์ที่เลือก
                if(image.length>0){ // ถ้ามีการเลือกไฟล์ 
                    showThumbnail(image);
                    drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
                    var formData = new FormData();
                    console.log(image);
                    // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
                    for (var i = 0; i < image.length; i++) {
                        formData.append('picture[]', image[i]);
                    }
                    //formData.append('picture', image[0]);

                    uploadFormData(formData) // ส่งข้อมูลไปัยัง server
                    .then( response => { // เมื่อส่งข้อมูลกลับมา
                        console.log( response ); // JSON data 
                        if(response.status=="OK"){
                            drop_guide.classList.remove('process');
                            drop_guide.classList.add('success');
                            drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                                    response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                                thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                            },3000);
                        }else{
                            drop_guide.classList.remove('process');            
                            drop_guide.innerHTML = response.text;
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                                thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                            },3000);            
                        }
                    });


                }

            });   
            fileInput.click(); // ให้ input file ถูกคลิก หลังจากสร้าง        
        }else{
            fileInputDOM.click(); // ให้ input file ถูกคลิก ตัวที่ถูกสร้างแล้ว
        }

    }    

    // ฟังก์ชั่นวนรูปสร้างรูปตัวอย่างที่กำลังอัพโหลด
    function showThumbnail(files){
   
       for(var i=0;i<files.length;i++){
           var file = files[i]
           var fileName = file.name;
           var imageType = /image.*/
           if(!file.type.match(imageType)){
               //     console.log("Not an Image");
               continue;
           }
  
           var image = document.createElement("img");
           var wrapImg = document.createElement("div");
           var thumbnail = document.getElementById("thumbnail");
           wrapImg.setAttribute("data-file", fileName);
           image.file = file;
           wrapImg.appendChild(image);
           thumbnail.appendChild(wrapImg);
  
           var reader = new FileReader();
           reader.onload = (function(aImg){
               return function(e){
                   aImg.src = e.target.result;
               };
           }(image))
  
           var ret = reader.readAsDataURL(file);
           var canvas = document.createElement("canvas");
           ctx = canvas.getContext("2d");
           image.onload= function(){
               ctx.drawImage(image,50,50)
           }
       } // end for loop
  
   } // end showThumbnail    
    

});
</script>
    
</body>
</html>


   เพิ่มเติมเนื้อหา ครั้งที่ 5 วันที่ 20-02-2024


การใช้งาน Axios แทน fetch เพื่อรองรับการแสดง Progress การอัพโหลด

 
เนื่องจากคำสั่ง fetch ไม่รองรับการแสดง progress หรือสถานะความก้าวหน้า
ในการอัพโหลด หรือเข้าใจง่ายๆ คือว่าอัพโหลดได้คิดเป็นกี่เปอร์เช็นต์แล้ว แบบนี้เป็นต้น
จึงมีตัวช่วยที่เราสามารถนำมาประยุกต์ใช้งานกับโค้ดเดิมเราได้ง่าย โดยปรับเพียงเล็กน้อย
เท่านั้น ก็คือใช้ Axios https://axios-http.com/docs/intro วิธีการก็คือเรียกใช้งาน
ไฟล์ axios.min.js โดยเพิ่มโค้ดส่วนนี้เข้าไป
 
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
 
 แล้วเปลี่ยน การเรียกใช้คำสั่ง fetch เป็น axios ดังนี้
 
    const response_async =  await fetch('ajax_draganddrop.php?upload', {
        method: "POST",  
        body: formData // ส่งข้อมูลฟอร์ม
    });    
 
เปลี่ยนเป็น
 
    const response_async =  await axios.post('ajax_draganddrop.php?upload', formData, { 
        onUploadProgress: (progressEvent) => {
            const { loaded, total } = progressEvent;
            let precentage = Math.floor((loaded * 100) / total);
            progressBar.style.width = precentage+"%";
        //    console.log(precentage);
        },
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    });
 
ดูโค้ดตัวอย่างทั้งหมด ajax_draganddrop.php

<?php
if(isset($_GET['upload'])){
 
if (!empty($_FILES['picture'])) {    
    if(is_array($_FILES['picture']['name'])){
        $num_success = 0; // จำนวนอัพโหลดสำเร็จ
        $num_upload = count($_FILES['picture']['name']); // จำนวนไฟล์ทั้งหมด
 
        for($i = 0; $i < $num_upload; $i++){
            if (is_uploaded_file($_FILES['picture']['tmp_name'][$i])) {
                $sourcePath = $_FILES['picture']['tmp_name'][$i];
                $targetPath = "uploads/" . $_FILES['picture']['name'][$i];
                if (move_uploaded_file($sourcePath, $targetPath)) {
                    $num_success++; 
                }
            }
        }
        $response = array(
            "status"=>"OK",
            "num_success"=>$num_success,
            "num_upload"=>$num_upload
        );  
    }else{
        $response = array(
            "status"=>"Fail"
        );    
    }
}else{
    $response = array(
        "status"=>"Fail"
    );
}
header("Content-Type: application/json");
echo json_encode($response);        
exit; 
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

<style>
.drop-place{
    margin: auto;
    width: 75%;
    height: 50px;
    border: 1px solid red;
    text-align: center;
    padding: 50px;
    font-size: 20px;
}
.drop-place.dragging{
    background: #C8EFD4;
}
.drop-place.dropped{
    background: #6BD089;
}
.drop-guide.process{
    color: yellow;
}
.drop-guide.success{
    color: blue;
}
.hidden-inputfile{
    width: 1px;
    height: 1px;
    visibility: hidden;
}
#thumbnail,div.removepic{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}
#thumbnail img{
    width:50px;
    height:50px;
    margin:5px;
}
canvas{
    border:1px solid red;
}    
.upload-progress-bar{
    width: 0px;
    height: 5px;
    background-color: greenyellow;
}
</style>
<div class="drop-place">
    <div class="upload-progress-bar"></div>
    <span class="drop-guide"><a href="#" class="choose-image">เลือกไฟล์</a> หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด</span>
    <div id="thumbnail"></div>
</div>
<div class="hidden-inputfile"></div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
    console.log("DOM fully loaded and parsed");
    const el = document.querySelector(".drop-place");    
    const drop_guide = document.querySelector(".drop-guide");    
    const thumbnail = document.querySelector("#thumbnail");    
    const progressBar = document.querySelector(".upload-progress-bar");
    // เมื่อลากไฟล์เข้ามาในพื้นที่ ทำงานครั้งเดียวเมื่อลากไฟล์เข้ามา
    el.addEventListener("dragenter", (event) => {
        event.preventDefault();
    //    console.log("DragEnter");
        drop_guide.innerHTML = 'ปล่อยไฟล์เพื่ออัพโหลด';
     //   var drag_image = event.originalEvent.dataTransfer.files;
    });
    // เมื่อลากไฟล์เข้ามาอยู่ด้านบนของพื้นที่ ส่วนนี้จะทำงานตลอดที่ไฟล์ที่ลากยังอยู่ในพื้ที่
    el.addEventListener("dragover", (event) => {
        event.preventDefault();
    //    console.log("DragOver");
        event.target.classList.add('dragging');
    });
    // เมื่อนำไฟล์ที่ลากออกนอกพื้นที่ จะทำงานครั้งเดียวเมื่่อลากไฟล์ออกนอกพื้นที่
    el.addEventListener("dragleave", (event) => {
        event.preventDefault();
    //    console.log("DragLeave");
        drop_guide.innerHTML = 'ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
        event.target.classList.remove('dragging');
    });
    // เมื่อวางหรือปล่อยไฟล์ที่ลากลงในพื้นที่ ทำงานครั้งเดียว
    el.addEventListener("drop", (event) => {
        event.preventDefault();
        console.log("Drop");
        drop_guide.classList.add('process');
        event.target.classList.remove('dragging');
        event.target.classList.add('dropped');
        // ตัวแปรเก็บข้อมูลไฟล์ ที่ลากมาวางเพื่ออัพโหลด
        var image = event.dataTransfer.files;
        showThumbnail(image);
        drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
        var formData = new FormData();
        console.log(image);
        // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
        for (var i = 0; i < image.length; i++) {
            formData.append('picture[]', image[i]);
        }
        //formData.append('picture', image[0]);

        uploadFormData(formData) // ส่งข้อมูลไปัยัง server
        .then( response => { // เมื่อส่งข้อมูลกลับมา
            console.log( response ); // JSON data 
            if(response.status=="OK"){
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');
                drop_guide.classList.add('success');
                drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                        response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                    thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                    progressBar.style.width = "0px";
                },3000);
            }else{
                event.target.classList.remove('dropped');
                drop_guide.classList.remove('process');            
                drop_guide.innerHTML = response.text;
                setTimeout(()=>{
                    drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                    drop_guide.classList.remove('success');
                    thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                    progressBar.style.width = "0px";
                },3000);            
            }
        });


    });

    // ฟังก์ชั่่ง ajax ส่งข้อมูลไปยัง server และต้องรอข้อมูลกลับมาก่อนนำไปใช้งาน
    async function uploadFormData(formData) {
        try{

            const response_async =  await axios.post('ajax_draganddrop.php?upload', formData, { 
                onUploadProgress: (progressEvent) => {
                    const { loaded, total } = progressEvent;
                    let precentage = Math.floor((loaded * 100) / total);
                    progressBar.style.width = precentage+"%";
                //    console.log(precentage);
                },
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            });

            console.log(response_async);
            // ต้อง(ไม่)เป็น 404 หรือ 500 คือ ไต้ไม่เป็น ไม่พบไฟล์ หรือ server ไม่ตอบสนอง
            if(![404,500].includes(response_async.status)){
                // กรณีใช้ axios ตรงนี้้จะต้องเรียกผ่าน data ซึ่งเป็น json ไม่ต้องแปลง
                return response_async.data; 
            }else{ // กรณี ไม่พบไฟล์ 
                var errors = {status:'Fail',text:'เกิดข้อผิดพลาดลองใหม่อีกครั้ง'};
                return errors;
            }
        }catch (error) { // ส่วนใหญ่เป็นกรณี 500 หรือ server ไม่ตอบสนอง
            console.error(error);
            var errors = {status:'Fail',text:'การเชื่อมต่อ server ไม่ตอบสนอง'};
            return errors;
        }
    }   

    // กำหนด event ให้กับปุ่ม เลือกไฟล์ สังเกตว่า เราไม่ได้กำหนดให้กับปุ่มโดยตรง
    // แต่กำหนดในกับ drop-place แทน แล้วค่อยไปตรวจสอบว่า ถ้าตัวที่คลิกเป็นปุ่ม
    // choose-image หรือไม่ ถ้าใช่ ให้ทำงาน ทั้งนี้ก็เพราะว่า ถ้าเรากำหนดโดยตรง
    // ปุ่มที่ถูกสร้างมาจาก javascript จะไม่ทำงาน วิธีนี้จึงเป็นการป้องกันปัญหานั้น
    el.addEventListener("click", (event) => {
        var chooseEl = event.target.closest('.choose-image');
        if (chooseEl) { // คลิกโดยปุ่ม เลือกไฟล์หรือไม่
            createUploadFileInput();
        }
        event.preventDefault();
    });

    // ฟังก์ชั่นสำหรับสร้าง input file ให้เลือก พร้อมให้รองรับการอัพโหลดไฟล์ เมื่อเลือกไฟล์
    function createUploadFileInput() {

        var fileInputDOM = document.querySelector('.image_upload');
        var placeForFileInput = document.querySelector('.hidden-inputfile');

        // ตรวจสอบว่า ถ้ายังไม่มี ให้ทำการสร้างขึ้นมาก่อน
        if (!fileInputDOM) {

            // ทำการสร้าง
            var fileInput = document.createElement('input');

            fileInput.type = 'file';
            fileInput.name = 'picture[]'
            fileInput.classList.add('image_upload');
            fileInput.multiple = true;
            fileInput.accept = 'image/*';
            placeForFileInput.appendChild(fileInput);

            // เมื่อมีการเลือกไฟล์ หรือเปลี่ยนแปลงการเลือกไฟล์
            fileInput.addEventListener("change", (event) => {
                event.preventDefault();
                console.log("choose file");
                var image = fileInput.files; // เก็บตัวแปรไฟล์ที่เลือก
                if(image.length>0){ // ถ้ามีการเลือกไฟล์ 
                    showThumbnail(image);
                    drop_guide.innerHTML = 'กำลังอัพโหลด '+image.length+' ไฟล์...';
                    var formData = new FormData();
                    console.log(image);
                    // วนลูปเพิ่มข้อมูลฟิลด์รูปแบบอาเรย์เข้าไป
                    for (var i = 0; i < image.length; i++) {
                        formData.append('picture[]', image[i]);
                    }
                    //formData.append('picture', image[0]);

                    uploadFormData(formData) // ส่งข้อมูลไปัยัง server
                    .then( response => { // เมื่อส่งข้อมูลกลับมา
                        console.log( response ); // JSON data 
                        if(response.status=="OK"){
                            drop_guide.classList.remove('process');
                            drop_guide.classList.add('success');
                            drop_guide.innerHTML = 'อัพโหลด '+response.num_success+'/'+
                                                    response.num_upload+' ไฟล์ เรียบร้อยแล้ว';
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                                thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                                progressBar.style.width = "0px";
                            },3000);
                        }else{
                            drop_guide.classList.remove('process');            
                            drop_guide.innerHTML = response.text;
                            setTimeout(()=>{
                                drop_guide.innerHTML = '<a href="#" class="choose-image">เลือกไฟล์</a>'+
                                                    ' หรือ ลากไฟล์มาวางที่นี่เพื่ออัพโหลด';
                                drop_guide.classList.remove('success');
                                thumbnail.innerHTML = ''; // ล้างข้อมูลรูปตัวอย่างที่แสดง
                                progressBar.style.width = "0px";
                            },3000);            
                        }
                    });


                }

            });   
            fileInput.click(); // ให้ input file ถึงคลิก หลังจากสร้าง        
        }else{
            fileInputDOM.click(); // ให้ input file ถึงคลิก ตัวที่ถูกสร้างแล้ว
        }

    }    

    // ฟังก์ชั่นวนรูปสร้างรูปตัวอย่างที่กำลังอัพโหลด
    function showThumbnail(files){
   
       for(var i=0;i<files.length;i++){
           var file = files[i]
           var fileName = file.name;
           var imageType = /image.*/
           if(!file.type.match(imageType)){
               //     console.log("Not an Image");
               continue;
           }
  
           var image = document.createElement("img");
           var wrapImg = document.createElement("div");
           var thumbnail = document.getElementById("thumbnail");
           wrapImg.setAttribute("data-file", fileName);
           image.file = file;
           wrapImg.appendChild(image);
           thumbnail.appendChild(wrapImg);
  
           var reader = new FileReader();
           reader.onload = (function(aImg){
               return function(e){
                   aImg.src = e.target.result;
               };
           }(image))
  
           var ret = reader.readAsDataURL(file);
           var canvas = document.createElement("canvas");
           ctx = canvas.getContext("2d");
           image.onload= function(){
               ctx.drawImage(image,50,50)
           }
       } // end for loop
  
   } // end showThumbnail    
    

});
</script>
    
</body>
</html>


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ







เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง










เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ