ジャンルから探す

Web Design English

Quillで画像をimgタグとして挿入する方法【Laravel】

この記事では、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の学習本を探してる方はこちらの記事をどうぞ