0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MT困りごと カスタムスクリプトにてinnerHtmlで取った要素を出力しても改行されない

0
Posted at

mtのカスタムブロックでアコーディオンの開く部分をテキストボックスから出力したい。 innerHTMLで要素の中身を取って来るのですが、表示する時に改行コードが抜けます

ポイントは、

innerHTMLで取ったテキストは、そのままでは「改行=表示上の改行」にならない

というところです。

「抜けている」というより、「HTMLとしては存在するけどレイアウト上折り返されていない/正規化されている」状態になっている可能性が高いです。


なぜ改行が消えたように見えるのか?

① innerHTML は「HTML文字列」を返す

たとえばエディタ側のDOMがこうだとして:

<div class="acc-body">1行目
2行目
3行目</div>
const body = document.querySelector('.acc-body').innerHTML;
  • body の中身は "1行目\n2行目\n3行目" のような文字列になります(環境によっては \r\n)。
  • これをそのまま
MTBlockEditorSetCompiledHtml(`
  <div class="accordion__panel">${body}</div>
`);

とすると、フロント側では HTMLのテキストノード内の改行 になります。

HTMLの標準動作では、white-space: normal の要素内では

  • 連続スペース・改行・タブなどは「1つのスペース」にまとめられる

ので、見た目上は

1行目 2行目 3行目

みたいに全部つながって見える=「改行が消えたように見える」わけです。


解決パターン 3つ

パターンA:CSSで white-space: pre-line を指定する(JSいじり少なめ)

表示側のアコーディオンの中身にクラスをつけて、CSSで改行を活かす方法です。

1. カスタムブロックスクリプト例

<script>
document.addEventListener('DOMContentLoaded', () => {
  if (document.body.dataset.hasCompiledHtml) return;

  const title = document.querySelector('.acc-title')?.textContent || '';
  const body  = document.querySelector('.acc-body')?.textContent || '';

  MTBlockEditorSetCompiledHtml(`
    <div class="c-accordion">
      <button class="c-accordion__head">${title}</button>
      <div class="c-accordion__panel js-accordion-panel">
        ${body}
      </div>
    </div>
  `);
});
</script>

.acc-body<textarea> の場合は .value を使います:

const body = document.querySelector('.acc-body')?.value || '';

2. CSSで改行を活かす

.c-accordion__panel {
  white-space: pre-line;
}
  • pre-line

    • 改行コード(\n)→ 実際の改行として表示
    • それ以外のスペースは通常通り

という挙動なので、「テキストエリアの感覚」に近くなります。

まずは これを試すのが一番楽 です。


パターンB:JSで \n<br> に変換してしまう

「どうしても <br> にしておきたい」「HTMLメール的な出力にしたい」という場合は、JS側で変換します。

<script>
document.addEventListener('DOMContentLoaded', () => {
  if (document.body.dataset.hasCompiledHtml) return;

  const title    = document.querySelector('.acc-title')?.textContent || '';
  const bodyRaw  = document.querySelector('.acc-body')?.value || ''; // textarea想定
  const bodyHtml = bodyRaw
    .replace(/\r\n/g, '\n')  // 改行コードを揃える(Windows対策)
    .replace(/\r/g, '\n')
    .replace(/\n/g, '<br>'); // 改行 → <br>

  MTBlockEditorSetCompiledHtml(`
    <div class="c-accordion">
      <button class="c-accordion__head">${title}</button>
      <div class="c-accordion__panel js-accordion-panel">
        ${bodyHtml}
      </div>
    </div>
  `);
});
</script>
  • この方法では、保存されるHTML自体が <br> に置き換わります。
  • CSSでの white-space 指定は不要です。

パターンC:innerHTML ではなく textContent / value を使う

今、

innerHTMLで要素の中身を取って来るのですが…

と書いてくれたので、ここも重要ポイントです。

  • テキストボックス / textarea の値.value
  • 通常の要素内テキスト → .textContent
  • HTML(タグ含め)ごと欲しい → .innerHTML

アコーディオンの「開く部分」は基本テキストだけのことが多いので、

  • 安全・素直 なのは .textContent / .value
  • .innerHTML は「ユーザーが <br><strong> など直接入れる」ケース向き

です。

もし今こんな感じなら:

const body = document.querySelector('.acc-body').innerHTML;

いったんこう変えてみてください:

// テキストエリアの場合
const body = document.querySelector('.acc-body').value || '';

// divなどの場合
const body = document.querySelector('.acc-body').textContent || '';

その上で

  • CSSで white-space: pre-line を指定する(パターンA)
  • もしくは JS で <br> に変換する(パターンB)

のどちらか、という構成にすると安定します。


「ブログ記事のサンプル」っぽくまとめる書き方(おまけ)

もしこのネタを自分のブログやメモに残すなら、こんな感じで構成しておくと後で見返しやすいです:

  • カスタムブロック構成(親:アコーディオン、子:アコーディオンユニット)
  • エディタ内HTML構造(.acc-title, .acc-body
  • カスタムスクリプト(textContent / value + white-space: pre-line パターン)
  • フロント側のCSS(アコーディオン開閉+white-space

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?