この記事では、Quillエディタで画像を <img> タグとして本文に挿入する方法を解説します。
結論から書くと、Quill標準の画像ボタンは画像をBase64で埋め込むため、実運用には向きません。サーバーにアップロードしてURLを挿入する形に差し替える必要があります。
スポンサーリンク
Quillエディタの初期化
Quillエディタを使う準備が整ったら、次は実際にエディタを初期化する作業です。JavaScriptを使って、Quillエディタを適用する対象のtextarea要素を特定し、その上でエディタを初期化します。
#editorがIDとして設定されたtextarea要素に対してQuillエディタが初期化されます。
const quill = new Quill('#editor', {
theme: 'snow'
});
画像を添付できるQuillモジュール
Quill 本体には、画像をサーバーへアップロードする機能はありません。ツールバーの画像ボタンは、選んだ画像をBase64に変換して本文に直接埋め込むだけです。
そのままだと本文のHTMLが画像データごと肥大化し、データベースに巨大な文字列が保存されることになります。実運用では、画像をサーバーに送ってURLだけを埋め込む形に差し替えるのが定石です。
これを実現するには、サードパーティのモジュールを使うか、自分で画像ボタンのハンドラを差し替えます。以下は前者の設定例です。
下記のコードは、Quillエディタに画像を添付するためのオプション設定とコールバック処理の例です。必要に応じて、uploadUrlを適切な画像アップロード処理が実装されたエンドポイントに変更してください。
// 画像添付のオプションを定義
const options = {
uploadUrl: '/upload', // 画像をアップロードするURLを指定
method: 'POST', // HTTPリクエストメソッドを指定
name: 'image', // アップロードするファイルのフィールド名を指定
withCredentials: false, // クロスオリジンリクエストで認証情報を送信しないように指定
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}' // CSRFトークンを指定(Laravelの場合)
},
// 画像をアップロードする際の成功・失敗時の処理を定義
callbackOK: (serverResponse, next) => {
next(serverResponse.url);
},
callbackKO: serverError => {
console.log(serverError);
}
};
// 画像添付モジュールを初期化
const imageHandler = function() {
const range = this.quill.getSelection(true);
this.quill.updateContents(new Delta().retain(range.index).delete(range.length).insert({ image: 'loading.gif' }), 'user');
this.quill.setSelection(range.index + 1);
var fileInput = this.container.querySelector('input.ql-image[type=file]');
if (fileInput == null) {
fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon');
fileInput.classList.add('ql-image');
fileInput.addEventListener('change', () => {
var formData = new FormData();
formData.append(options.name, fileInput.files[0]);
fetch(options.uploadUrl, {
method: options.method,
headers: options.headers,
body: formData,
credentials: options.withCredentials ? 'include' : 'omit'
}).then(response => {
if (response.ok) {
return response.json();
}
return Promise.reject(response.statusText);
}).then(data => {
options.callbackOK(data, url => {
this.quill.insertEmbed(range.index, 'image', url, 'user');
this.quill.setSelection(range.index + 1);
});
}).catch(error => {
console.error('Upload failed');
options.callbackKO(error);
});
});
this.container.appendChild(fileInput);
}
fileInput.click();
};
quill.getModule('toolbar').addHandler('image', imageHandler);
スポンサーリンク
自分でハンドラを書く場合
結論:モジュールを入れずに、画像ボタンの動作だけを差し替えることもできます。
const toolbar = quill.getModule('toolbar');
toolbar.addHandler('image', function () {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const file = input.files[0];
const formData = new FormData();
formData.append('image', file);
const res = await fetch('/upload', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content },
body: formData,
});
const data = await res.json();
// 現在のカーソル位置に画像を挿入する
const range = quill.getSelection(true);
quill.insertEmbed(range.index, 'image', data.url);
quill.setSelection(range.index + 1);
};
});
CSRFトークンは <meta name="csrf-token"> から読むのが確実です。Bladeの {{ csrf_token() }} をJavaScriptの文字列に直接埋め込む書き方は、外部ファイルに切り出したときに動かなくなります。
<meta name="csrf-token" content="{{ csrf_token() }}">
関連する記事
Quillの導入がまだの場合は、Laravelにリッチテキストエディタ『Quill』を実装するから先にどうぞ。Quill 2.0でCDNの配布元が変わっています。
Ajaxでのアップロード処理をサーバー側まで含めて実装する手順は、Quillの画像をAjaxを使ってサーバーにアップロードする方法にまとめました。
ツールバーのボタン自体をカスタマイズする方法はQuillのツールバーにカスタムボタンを追加するをどうぞ。
まとめ
この記事では、Quillエディタにimgタグを使用して画像を添付する方法をサンプルコードを含めて解説しました。
▼HTML/CSS/JavaScriptの学習本を探してる方はこちらの記事をどうぞ
