iT邦幫忙

0

前端圖片上傳「排序」的程式,該如何寫?

請教各位先進

小弟目前有寫好 前端 「多張圖片上傳,且可預覽」的功能了
但忽然發現,多張圖片選好後,發生「排序」無法依照原本我自己在選擇圖片時的「順序」來做排序

例如:我在選擇圖片時 選了 d、c、a、b 預覽的時候 卻顯示出 b、a、c、d
而我是希望 在顯示圖片的時候,也一樣是按照順序
d、c、a、b來顯示....

請問有現有 已經寫好的「模組」等 可以直接套用的嗎?
比如 有人寫好 且好評的javascript可直接修改套用?

還是有一些 該如何寫程式的 邏輯可參考的嗎?
註:排序 也包括可以圖片預覽。

感謝大家的幫忙^^

1
阿展展展
iT邦好手 1 級 ‧ 2019-11-25 13:43:55

如果只要排序,那妳可以多給一個自動遞增的參數( id 或 num 或.... 隨便啦)
就可以確保上傳上來的圖片照著順序排

你的這個問題,比起如何上傳成功,難易度差蠻多的
圖片上傳比較難做吧?

4
dragonH
iT邦超人 6 級 ‧ 2019-11-25 13:48:14

給定 排序id

然後前端可以用 sort 排序

再來用迴圈印出來

code

const images = [
    {
		name: 'test002',
		order: 2,
	},
	{
		name: 'test001',
		order: 1,
	},
	{
		name: 'test003',
		order: 3,
	},
];

images.sort((a, b) => a.order - b.order)

result

	{
		name: 'test001',
		order: 1,
	},
    {
		name: 'test002',
		order: 2,
	},
	{
		name: 'test003',
		order: 3,
	},

預覽範例

codepen

不過預設應該會照你 file picker 看到的排序來排

好像跟選取順序無關

所以你想要照你的意思來排序的話

可能需要寫一個讓 user 排序的功能

看更多先前的回應...收起先前的回應...
jerry168 iT邦新手 5 級 ‧ 2019-11-25 14:39:08 檢舉

謝謝 dragonH 細心的回覆^^
我剛進入 預覽範例 查看, 然後我選擇了 四張圖片,不過我發覺 底下 預覽 跑出來的四張圖片,一樣 沒有按照我在「選擇四張圖片」時的順序,來 按照當時的順序 去排序出來顯示,
例如:我在選擇圖片時 選了 d、c、a、b
預覽的時候 顯示出
b、a、c、d

請問 排序這方面有 解決方法嗎? 或者是 可以 在顯示出的 四張圖片裡,我可以 「自行決定」那一張圖片要排在那一張?或可當為「封面」?
謝謝您

dragonH iT邦超人 6 級 ‧ 2019-11-25 14:41:21 檢舉

jerry168

預設會照你在選檔案時

看到的情況排序

所以你想要照你的意思排序

可能就必須另外寫一個讓 user 排序的功能

jerry168 iT邦新手 5 級 ‧ 2019-11-25 14:44:16 檢舉

應該說 我的狀況是

例如:我在選擇圖片時 選了 d、c、a、b
預覽的時候 卻顯示出 b、a、c、d

而我是希望 在顯示圖片的時候,也一樣是按照順序
d、c、a、b來顯示....

dragonH iT邦超人 6 級 ‧ 2019-11-25 14:54:14 檢舉

jerry168

我知道你的意思呀

我 codepen 改好了

可以參考一下

jerry168 iT邦新手 5 級 ‧ 2019-11-25 15:01:46 檢舉

dragonH

我剛進入 codepen了, 我一樣選擇四張圖片
順序 d、c、a、b
然後我看到您 預覽的圖片 旁邊多了輸入輸入框
1,2, 3, 4 這個應該是順序的意思

不過 這個1 ~ 4的順序,還真的 沒有跟我原本選擇的
d、c、a、b
這個順序來顯示圖片

我自己剛查了一下資料, 會發生這樣的結果
可能是因為 在上傳圖片用for迴圈的時候, 別的順序的圖片可能上會先上傳成功,所以就打亂了原本我自己選擇的圖片順序

是因這個原因嗎? ><

dragonH iT邦超人 6 級 ‧ 2019-11-25 15:08:21 檢舉

jerry168

原因或許這篇可以參考

可能是因為 在上傳圖片用for迴圈的時候, 別的順序的圖片可能上會先上傳成功,所以就打亂了原本我自己選擇的圖片順序

有可能

因為 js 是非同步

不會等你這圈的東西"完全"跑完才去跑下圈

不過我認為你的問題不是這個就是

所以解決的辦法就是

連同排列順序一起送到後端

jerry168 iT邦新手 5 級 ‧ 2019-11-25 15:18:34 檢舉

dragonH
「連同排列順序一起送到後端」 我思考一下 我該怎麼做
謝謝您 立刻跟我回覆
我晚點 如果有進展,我po上來 與您分享

dragonH iT邦超人 6 級 ‧ 2019-11-25 15:21:15 檢舉

/images/emoticon/emoticon12.gif

jerry168 iT邦新手 5 級 ‧ 2019-11-25 23:55:41 檢舉

dragonH
我搞一天了 ><

我正在 實驗 這個網址
https://www.codehim.com/demo/jquery-image-uploader-preview-and-delete/
您可以直接執行裡面的「 Example 1 - basic usage」試試。

但是我目前卡在 前端送出的post值到後端 卻都接不到,很頭痛

不知您 有其它 可行的解決方法嗎?

沒有排序 也沒關係 ,只要能做出 像上面這個網址 一樣的功能就可以了 ....><

因為上面這個網址,至少 可以讓我delete圖片,然後我可以「先上傳第一張」之後 我再點選 就可以再上傳後面的照片上去。
這樣至少 也可以讓我達到 我可以「自訂」我的照片的「第一張」是什麼圖片.....
然後 我今天有 找到 jquery-file-upload 的套件,但我發現很不好懂,不好用,所以後來也放棄不用。

dragonH iT邦超人 6 級 ‧ 2019-11-26 00:09:29 檢舉

jerry168

刪除很簡單啊

對 array 用 splice 拿掉就好

晚點再補範例

jerry168 iT邦新手 5 級 ‧ 2019-11-26 02:29:07 檢舉

dragonH
我剛找到這個code
https://www.codeproject.com/Articles/1208892/Lightweight-Multiple-File-Upload-with-Thumbnail-Pr?fid=1927286&df=90&mpp=25&sort=Position&spc=Relaxed&prof=True&view=Normal&fr=1#xx0xx

寫的不錯,功能也是我想要的。
不過我實際測試的時候,發現當我先選擇「1張圖片」之後我再按選擇圖片的時候,例如我再選擇「2張圖片」這時候 應該整個list會有3張圖片,而畫面上也確實顯示3張,但我用alert跳出來卻只有顯示最後的動作「2張圖片」, 若您有空檔,可否將以下code全部貼到一個html檔,直接執行即可。
在選擇圖片的時候,我有加入alert跳出 目前「總圖片長度」的數字出來,我覺得這裡有錯誤,但不知怎改..... ><

code如下
https://pastebin.com/umrFGWsU

豬豬人 iT邦新手 5 級 ‧ 2019-11-26 08:54:54 檢舉

你每一筆資料都要額外存成陣列,然後再加入一個主要陣列。會顯示三張是因為顯示跟input沒有相關,你先選的會被後選的覆蓋,所以顯示是三張,但是input裡的資料已經覆蓋掉第一張,所以實際只有兩張,所以才要自己存成陣列。(input裡的資料是屬於"偽陣列")

dragonH iT邦超人 6 級 ‧ 2019-11-26 09:45:44 檢舉

你的 event 只會取得當下的檔案數

你要取得所有的

就必須往某個 array 加

codepen

詳細可以看我上ㄧ個codepen

jerry168 iT邦新手 5 級 ‧ 2019-11-26 12:47:18 檢舉

dragonH
我剛有 看您上一個codepen了 ,大致只有懂70% ><
然後 我剛測試了一下 ,我有傳給您的那個連結內的code 裡面有一個
AttachmentArray
這個看來就是 作者有另外存的一個array。

我試著 想從js 裡將 AttachmentArray 塞到
document.getElementById("files"); 也就是
document.getElementById("files").value = AttachmentArray;

然後 就可以post 到後端 ,後端再去接 這個 getPost['files']
這樣可以嗎?

當然 我執行 document.getElementById("files").value = AttachmentArray;的時候出錯了 ,訊息是..

TestFileUpload.html:345 Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

以上 我的邏輯 有誤嗎? 謝謝

dragonH iT邦超人 6 級 ‧ 2019-11-26 22:46:28 檢舉

jerry168

我記得 input(type = "file") 不能用 js 來更改值唷

因為安全性的問題

所以不用想著如何把值塞回 input

你可以直接把最後的 array 結果

用 ajax 往後端送就好

0
豬豬人
iT邦新手 5 級 ‧ 2019-11-26 08:51:05

這是我之前做的,你參考看看,主要是把inuput的資料先存入陣列,再用FileReader讀檔顯示

<input type="file" id="files" multiple>
<div id="a"></div>
<style>
    img{
        width:200px;
    }
</style>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
var fileInput = document.getElementById('files');
var fileLists = [];
var files;
$('#files').on('change', function(event) {
    files = fileInput.files;    //重新取得[input type='file']資料
    show_img();
}); 

function show_img(){
    if(fileLists.length == 0){
        checked = 1;
    }

    files = Array.prototype.slice.call(files);  //將偽數組轉成陣列
        
    fileLists = fileLists.concat(files);  //concat() 方法用於連接兩個或多個數組(陣列)

    //顯示圖片資訊
    if (files.length !== 0) {
        for (var i = 0; i < files.length; i++) {
                var reader = new FileReader();              //FileReader 為預設物件,用來讀取檔案
                //Closure to capture the file information.
                reader.onload = (function(theFile) {        //讀取檔案後觸發onload
                    return function(e) {
                        var div = document.createElement('div');
                        div.className = 'img_wrap';
                        let target = e.target.result;
                        let file_name = escape(theFile.name);
                        var html_img = '<div class="drop-left"></div>'+
                                        '<div class="img_wrap">'+
                                            '<img class="upload_img" value="0" src="'+target+
                                            '"  title="'+file_name+'"/>'+
                                        '</div>'+
                                        '<div class="drop-right"></div>';
                        $('#a').append(html_img)                
                    };
                })(files[i]);
                reader.readAsDataURL(files[i]);         //讀取檔案後執行load事件
        }      
    }
    event.target.value = "";                            //讓剛被刪除的圖片可重複上傳
}
</script>
看更多先前的回應...收起先前的回應...
jerry168 iT邦新手 5 級 ‧ 2019-11-26 12:50:51 檢舉

cheer0101
謝謝您 無私的分享
我剛仔細的 測試跟研究了您的code ,您寫的很容易讓人明白
對我很有幫助 ^^ 尤其我也才了解到
Array.prototype.slice.call 的用法 ,真的很棒 ^^
您的code裡 有使用
fileLists = fileLists.concat(files);

那因我要將照片list 傳到後端去接收。
我可否 再將fileLists的值 塞回到
<input type="file" id="files" multiple>
裡面呢?
否則我不知如何將 fileLists 去post傳到後端?
謝謝您

豬豬人 iT邦新手 5 級 ‧ 2019-11-26 14:16:15 檢舉

傳入後端可以用ajax去寫喔,直接抓顯示出來的圖片,我顯示時是用base64去顯示的喔,可以往這方向找找看

豬豬人 iT邦新手 5 級 ‧ 2019-11-26 17:22:38 檢舉

傳base64,在後端讀base64存檔

jerry168 iT邦新手 5 級 ‧ 2019-11-26 21:36:02 檢舉

cheer0101
我下午開始研究ajax傳檔到後端....目前有一點進展了
目前我還在繼續實作測試中.....晚點若有進展再來跟您分享

jerry168 iT邦新手 5 級 ‧ 2019-11-26 23:17:31 檢舉

cheer0101

目前測試進度如以下程式連結:

https://pastebin.com/vuwkwmHS

直接copy 裡面code 存成html 即可執行..

重點可看 程式 第354行 console.log(file_data[i]);

第359行 console.log(AttachmentArray[i]);

在這頁code裡 當觸發 <input type="file" name="files[]" id="files" multiple...
的時候 或者做 「移除圖片」的時候 都會存到 AttachmentArray

所以 我最終是想將 這個AttachmentArray 存到FormData 然後用ajax傳送到後端去接收

而我在程式第348行
var file_data = $('#files').prop('files'); //取得上傳檔案屬性

有故意先用這行 程式去取得原本 input file 選取時讀出的檔案,而用這個直接加入到FormData用ajax
是可以傳送到後端的

但用AttachmentArray 加入到FormData要傳到後端 就似乎不可行

我用console.log分別將 AttachmentArray 跟 file_data 都讀出來

您可以選擇 個2、3張圖片 ,按下按鈕「顯示目前input files裡總圖片量」
看看log出來的訊息

不知您會有空幫我看看嗎? ^^

[註:目前我自己覺得 FormData.append()裡面必須引入Blob類別或其子類別 ex: File才行],所以還不知array如何轉File..
不過這個AttachmentArray好像是JSON格式... 我正在研究如何ajax裡再將json傳到後端去..

謝謝

jerry168 iT邦新手 5 級 ‧ 2019-11-28 01:09:46 檢舉

cheer0101
謝謝您 提示我用base64傳到後端
我今天試了一天,最後有順利在後端接收到base64,並存成圖片了。
目前雖然還沒全部測試完,但至少有重點進展,謝謝您的幫忙 ^__^

豬豬人 iT邦新手 5 級 ‧ 2019-11-29 08:31:50 檢舉

也可以研究一下canvas的應用喔

jerry168 iT邦新手 5 級 ‧ 2019-11-30 11:45:10 檢舉
豬豬人 iT邦新手 5 級 ‧ 2019-12-01 18:42:36 檢舉

yes

我要發表回答

立即登入回答