データをファイルとしてダウンロードする

データをファイルとしてダウンロードするには、データをBlob(バイナリ―データのオブジェクト)で扱い、それをURLにしてa要素のhref属性に指定し、download属性を付けてイベントを発火させることで実現することができます。
具体的には次のようなコードで実装することができます。

  • ※ ここでご紹介するコードはIEに対応していません。

文字列(テキスト)をダウンロード

文字列(テキスト)をダウンロードする場合は、次のようなコードで可能です。

JavaScript

/**
 * テキストデータのダウンロード
 * @param {string} text ダウンロードする対象となるテキスト
 * @param {string} fileName ファイル名
 * @param {string} [mimeType="text/plain"] テキストの種類(MIMEタイプ)
 * @param {boolean} [withBOM=false] BOM付きにするかどうか
 */
const textDownload = (text, fileName, mimeType = 'text/plain', withBOM = false) => {
	let data = [];

	// BOM付きにしたい場合
	if (withBOM) data.push(new Uint8Array([0xef, 0xbb, 0xbf]));

	data.push(text);

	const blob = new Blob(data, { type : mimeType });

	// a要素の生成
	const anchorElem = document.body.appendChild(document.createElement('a'));
	anchorElem.setAttribute('href', URL.createObjectURL(blob));
	anchorElem.setAttribute('target', '_blank');
	anchorElem.setAttribute('download', fileName);
	anchorElem.style.visibility = 'hidden';

	// イベント実行
	anchorElem.dispatchEvent(new MouseEvent('click', {
		view       : window,
		bubbles    : false,
		cancelable : false
	}));

	document.body.removeChild(anchorElem);
};

// ダウンロード実行
textDownload('あいうえお\nかきくけこ', 'sample.txt');

12行目はBOM付きにしたいときの処理です。
例えばCSVの場合、Excelでそのまま開くと文字化けしてしまいますが、BOM付きにすることで回避することができます 。

16行目のBlobオブジェクトでダウンロードするテキストの文字列とその種類(MIMEタイプ)を指定しています。
Blobの第一引数は配列で指定する必要がありますが、文字列の場合は改行で分割などはする必要がなく、そのまま配列の値として設定します。

19行目~23行目はa要素を作成しています。
a要素のdownload属性による機能でダウンロードを行うためのものです。
href属性には、URL.createObjectURLメソッドを使用して、引数にblobを指定してURL(URLスキーム)を生成したものを指定します。

26行目~30行目はa要素に対してクリックイベントを付与し、発火しています。
dispatchEventメソッドでイベントを発火、引数に対象のイベントとしてMouseEventオブジェクトでクリックイベントを作成しています。

32行目はダウンロード実行後は不要となるため、a要素を削除しています。

なお、ファイルの文字コードは、JavaScriptやHTMLの文字コードに関係がなく、基本的にUTF-8で出力されます。

Canvasデータのダウンロード

Canvasデータをダウンロードする場合は、次のようなコードで可能です。

JavaScript

/**
 * Canvasデータのダウンロード
 * @param {HTMLCanvasElement} canvasElem ダウンロードする対象のcanvas要素
 * @param {string} fileName ファイル名
 * @param {string} [mimeType="image/png"] 画像の形式(MIMEタイプ)
 * @param {number} [quality=1] 画像の品質(1~0の間で指定)
 */
const canvasDownload = (canvasElem, fileName, mimeType = 'image/png', quality = 1) => {
	// a要素の生成
	const anchorElem = document.body.appendChild(document.createElement('a'));
	anchorElem.setAttribute('href', canvasElem.toDataURL(mimeType, quality));
	anchorElem.setAttribute('target', '_blank');
	anchorElem.setAttribute('download', fileName);
	anchorElem.style.visibility = 'hidden';

	// イベント実行
	anchorElem.dispatchEvent(new MouseEvent('click', {
		view       : window,
		bubbles    : false,
		cancelable : false
	}));

	document.body.removeChild(anchorElem);
};

// ダウンロード実行
canvasDownload(document.querySelector('canvas'), 'sample.png');

11行目のhref属性には、toDataURLメソッドによってcanvasをURL(URLスキーム)へ生成したものを指定します。
toDataURLメソッドの第一引数は画像の形式(MIMEタイプ)、第二引数に画像の品質を指定します。

17行目~21行目はa要素に対してクリックイベントを付与し、発火しています。
dispatchEventメソッドでイベントを発火、引数に対象のイベントとしてMouseEventオブジェクトでクリックイベントを作成しています。

23行目はダウンロード実行後は不要となるため、a要素を削除しています。

Fetch APIなど非同期通信からダウンロード

JavaScript

/**
 * URLからダウンロード
 * @param {string} url ダウンロードするURL
 * @param {string} fileName ファイル名
 */
const downloadFromURL = async (url, fileName) => {
	const response = await fetch(url);

	if (response.status === 200) {
		const blob = await response.blob();

		// a要素の生成
		const anchorElem = document.body.appendChild(document.createElement('a'));
		anchorElem.setAttribute('href', URL.createObjectURL(blob));
		anchorElem.setAttribute('target', '_blank');
		anchorElem.setAttribute('download', fileName);
		anchorElem.style.visibility = 'hidden';

		// イベント実行
		anchorElem.dispatchEvent(new MouseEvent('click', {
			view       : window,
			bubbles    : false,
			cancelable : false
		}));

		document.body.removeChild(anchorElem);
	} else {
		alert('対象ファイルのアクセスに失敗しました。');
	}
};

// ダウンロード実行
downloadFromURL('https://www.example.co.jp/foo/bar.png', 'sample.png');

7行目でfetch関数を使用してURLへアクセスします。

10行目でblobメソッドでfetchからの内容をBlobで受け取ります。

13行目~17行目はa要素を作成しています。
a要素のdownload属性による機能でダウンロードを行うためのものです。
href属性には、URL.createObjectURLメソッドを使用して、引数にblobを指定してURL(URLスキーム)を生成したものを指定します。

20行目~24行目はa要素に対してクリックイベントを付与し、発火しています。
dispatchEventメソッドでイベントを発火、引数に対象のイベントとしてMouseEventオブジェクトでクリックイベントを作成しています。

26行目はダウンロード実行後は不要となるため、a要素を削除しています。

JavaScript逆引きリファレンス一覧へ戻る