2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaScript ドラッグ&ドロップされたテキストファイルの内容を表示する

Last updated at Posted at 2023-05-05

はじめに

File System Access APIを使用しない

File APIのみでファイルの内容を読み込みます。

ファイルが1つの場合

通常

まずは外見を作成します。

<!DOCTYPE html>
<html>
<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }
        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script></script>
</head>
<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea" class="textview"></div>
</body>
</html>

ページの読み込み時(DOMContentLoaded)にイベント時の処理を追加します。

  • droparea内にファイルが入っているときの処理(dragover
  • droparea内にファイルがドロップされたときの処理(drop
//ページ読み込み時
window.addEventListener("DOMContentLoaded", function () {
    document.getElementById("droparea").addEventListener("dragover", dragover_handler);
    document.getElementById("droparea").addEventListener("drop", drop_handler);
});

//dropareaに入った場合の処理
function dragover_handler(ev) {
    //ここにdropareaに入った場合の処理を記載
}

//dropareaにドロップされた時の処理
function drop_handler(ev) {
    //ここにdropareaにドロップされた時の処理を記載
}

ファイルがdropareaに入った場合の処理を作成します。

function dragover_handler(ev) {
    //既定の動作を行わない。
    ev.preventDefault();

    //マウスカーソルを+にする。
    ev.dataTransfer.dropEffect = "copy";
}

ファイルがdropareaにドロップされた時の処理を作成します。ev.dataTransfer.filesがドロップされたファイルです。分割代入で1つ目のファイルを取得します。ファイルが取得出来たらFileReaderを使ってファイの内容を取得します。

function drop_handler(ev) {
    //既定の動作を行わない。
    ev.preventDefault();

    //ドロップされたファイル
    const [file] = ev.dataTransfer.files;

    //FileReaderでテキスト読み込み。
    const reader = new FileReader();
    reader.onload = () => {
        //読み込み完了でファイル名と中身を表示。
        document.getElementById("textarea").innerText = file.name + "\n" + reader.result;
    };
    reader.readAsText(file);
    //reader.readAsText(file, 'shift-jis');//Shift-JISで読み込む場合
}

完成

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("load", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }

        //dropareaにドロップされた時の処理
        function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const [file] = ev.dataTransfer.files;

            //FileReaderでテキスト読み込み。
            const reader = new FileReader();
            reader.onload = () => {
                //読み込み完了でファイル名と中身を表示。
                document.getElementById("textarea").innerText = file.name + "\n" + reader.result;
            };
            reader.readAsText(file);
            //reader.readAsText(file, 'shift-jis');//Shift-JISで読み込む場合
        }
    </script>
</head>

<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea" class="textview"></div>
</body>

</html>

asyncを使用

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("DOMContentLoaded", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }

        //dropareaにドロップされた時の処理
        async function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const [file] = ev.dataTransfer.files;

            //ファイル読み込み
            const text = await getTextFromFile(file/*,'shift-jis'*/);

            //表示
            document.getElementById("textarea").innerText = file.name + "\n" + text;
        }

        //ファイルの内容を取得
        function getTextFromFile(file, encoding) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => {
                    resolve(reader.result);
                };
                reader.onerror = () => {
                    reject(new Error());
                };
                reader.readAsText(file, encoding);
            });
        }

    </script>
</head>

<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea" class="textview"></div>
</body>

</html>

CSVを表形式で表示

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        #dataview_cells {
            position: relative;
            overflow-x: auto;
            margin: 0 auto;
            background-color: #e5f1f5;
        }

        .cell {
            position: absolute;
            width: 100px;
            height: 20px;
            font-size: 15px;
            border: 1px solid rgb(97, 100, 102);
            padding: 1px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("DOMContentLoaded", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }

        //dropareaにドロップされた時の処理
        async function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const [file] = ev.dataTransfer.files;

            //ファイル読み込み
            const text = await getTextFromFile(file/*,'shift-jis'*/);

            //テキストを表に変換
            getTableFromText(text);
        }

        //ファイルの内容を取得
        function getTextFromFile(file, encoding) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => {
                    resolve(reader.result);
                };
                reader.onerror = () => {
                    reject(new Error());
                };
                reader.readAsText(file, encoding);
            });
        }

        //テキストを表に変換
        function getTableFromText(text) {

            const h = getElementPropertyPx(".cell", "height");
            const w = getElementPropertyPx(".cell", "width");
            const b = getElementPropertyPx(".cell", "border-width");
            const p = getElementPropertyPx(".cell", "padding");
            let tableheight;

            //データを区切って表に変換
            let inner = "";
            text.replace(/\r\n/g, '\n').split("\n").forEach((line, gyou) => {
                line.split(",").forEach((cell, retu) => {
                    let tate = (h + p * 2 + b) * gyou;
                    let yoko = (w + p * 2 + b) * retu;
                    inner += '<div class="cell" style="top:' + tate + 'px;left:' + yoko + 'px;">' + cell + '</div>';
                    tableheight = (h + p * 2 + b) * (gyou + 2);
                });
            });

            //表示
            document.getElementById("dataview_cells").style.height = String(tableheight) + "px";
            document.getElementById("dataview_cells").innerHTML = inner;
        }

        //要素のスタイル取得
        function getElementPropertyPx(str, pr) {
            let ele = window.getComputedStyle(document.querySelector(str));
            let val = ele.getPropertyValue(pr);
            return Number(val.replace("px", ""));
        }

    </script>
</head>

<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="dataview_cells">
        <div class="cell"></div>
    </div>
</body>

</html>

ファイルが複数の場合

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("DOMContentLoaded", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }
        let counter = -1;
        //dropareaにドロップした時の処理。
        function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const files = [...ev.dataTransfer.files];

            //ファイルの数だけ表示エリア作成
            let current_counter = counter;
            files.forEach(x => {
                counter++;
                document.getElementById("textareachild").outerHTML =
                    `<div id="textareachild${counter}" class="textview"></div>
                    <div id="textareachild"></div>`;
            });

            //ファイルの数だけ繰り返し
            files.forEach((file, i) => {
                //FileReaderでテキスト読み込み。
                const reader = new FileReader();
                reader.onload = () => {
                    //読み込み完了でファイル名と中身を表示。
                    document.getElementById(`textareachild${current_counter + i + 1}`).innerText = file.name + "\n" + reader.result;
                };
                reader.readAsText(file);
            });
        }
    </script>
</head>

<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea">
        <div id="textareachild"></div>
    </div>
</body>

</html>

File System Access APIを使用する

File System Access APIFileSystemHandleインターフェースを使用すると、ブラウザからローカルファイルの読み書きなどが一般的なソフトウェアのようにできるため非常に強力です。

FileSystemHandleの取得はまだ実験的な機能であり対応しているブラウザも限られます。

通常

FileSystemHandleを取得したうえで、File APIでファイルの内容を読み込みます。

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("DOMContentLoaded", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }
        //dropareaにドロップした時の処理。
        async function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const [item] = [...ev.dataTransfer.items].filter(item => item.kind === 'file');

            //ファイルハンドル取得
            handle = await item.getAsFileSystemHandle();

            //ファイル取得
            const file = await handle.getFile();

            //ファイル内容取得
            const text = await getTextFromFile(file/*, 'shift-jis'*/);

            //表示
            document.getElementById("textarea").innerText = text;
        }

        //ファイルの内容を取得
        function getTextFromFile(file, encoding) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => {
                    resolve(reader.result);
                };
                reader.onerror = () => {
                    reject();
                };
                reader.readAsText(file, encoding);
            });
        }
    </script>
</head>


<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea" class="textview"></div>
</body>

</html>

リアルタイムで表示を更新

ファイルが更新されると自動で表示内容を更新します。

<!DOCTYPE html>
<html>

<head>
    <style>
        #droparea {
            background-color: #e9f7c4;
        }

        .textview {
            background-color: #e5f1f5;
            margin-top: 10px;
        }
    </style>
    <script>
        //ページ読み込み時
        window.addEventListener("DOMContentLoaded", function () {
            document.getElementById("droparea").addEventListener("dragover", dragover_handler);
            document.getElementById("droparea").addEventListener("drop", drop_handler);
            setInterval(realtimePreview, 1000);
        });

        //dropareaに入った場合の処理
        function dragover_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //マウスカーソルを+にする。
            ev.dataTransfer.dropEffect = "copy";
        }
        //dropareaにドロップした時の処理。
        async function drop_handler(ev) {
            //既定の動作を行わない。
            ev.preventDefault();

            //ドロップされたファイル
            const [item] = [...ev.dataTransfer.items].filter(item => item.kind === 'file');

            //ファイルハンドル取得
            handle = await item.getAsFileSystemHandle();

            //状態リセット
            date = undefined;
            processing = finished = false;
        }

        //常時更新表示
        let handle;
        let processing = false;
        let finished = false;
        async function realtimePreview() {
            if (handle !== undefined && !processing && !finished) {
                processing = true;
                try {
                    const file = await handle.getFile();
                    const text = await getTextFromFile(file/*, 'shift-jis'*/);
                    if (typeof (text) == "string") {
                        document.getElementById("textarea").innerText = text;
                    }
                } catch (e) {
                    finished = true;
                }
                processing = false;
            }
        }

        //ファイルの内容を取得
        let date;
        function getTextFromFile(file, encoding) {
            if (date == undefined || file.lastModified > date) {
                date = file.lastModified;
                return new Promise((resolve, reject) => {
                    const reader = new FileReader();
                    reader.onload = () => {
                        resolve(reader.result);
                    };
                    reader.onerror = () => {
                        reject();
                    };
                    reader.readAsText(file, encoding);
                });
            } else {
                return Promise.resolve(0);
            }
        }
    </script>
</head>


<body>
    <div id="droparea">ここにテキストファイルをドロップ</div>
    <div id="textarea" class="textview"></div>
</body>

</html>
2
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?