開発eurekapu-nuxt4メモ

全取引SVGが一切表示されない

22取引分のアニメーション確認ページ(/dev/journal-push-animation-test)を開いたら、全コンポーネントが空白だった。エラーメッセージも出ない。Vue の警告もない。ただ何もない。

原因はすぐ分かった。コンポーネントの命名ルールを完全に読み違えていた。

ファイルの置き場はこうなっている。

app/components/dev/transactions/TransactionNo01Animated.vue

Nuxt の自動登録は、ディレクトリ階層をコンポーネント名のプレフィックスとして付加する。結果、このコンポーネントは DevTransactionsTransactionNo01Animated として登録された。試作ページは <TransactionNo01Animated> と書いていた。名前が噛み合っておらず、Nuxt はコンポーネントを静かに無視していた。

修正の方針は2つある。呼び出し側のタグ名をすべて書き直すか、登録側でプレフィックスを消すか。22個のコンポーネントがあるので、後者を選んだ。

// nuxt.config.ts
components: [
  { path: '~/components', pathPrefix: true },
  { path: '~/components/dev/transactions', pathPrefix: false },
],

pathPrefix: false を付けると、ディレクトリ階層がコンポーネント名に入らない。再起動後、no01 の SVG が画面に現れた。仕訳をプッシュすると株式券が右から左へ移動し、取消ボタンもアクティブになった。


CSS transform が SVG に効かない

no08(買掛金発生)のアニメーション実装で詰まった。買掛債務が発生する瞬間に「パーン」と広がる花火を入れたかった。

最初は CSS の @keyframes で書いた。

@keyframes spark {
  0%   { transform: scale(0) translate(0, 0); opacity: 1; }
  100% { transform: scale(1) translate(30px, -20px); opacity: 0; }
}

ブラウザで確認すると、花火の点が一切動かない。スケールもゼロのまま固定されている。

調べて分かったのは、SVG 要素に対して CSS の transform が期待通りに動かないケースがあること。特に transform-box: fill-box を指定していても、ブラウザの実装差によって変換の基点が狂う。transform: identity matrix に固定されているように見える状態になる。

CSS で組むのをやめて、SMIL に切り替えた。SVG が本来持っているアニメーション仕様だ。

<circle class="spark" cx="200" cy="150" r="4" fill="#ff6b35" opacity="1">
  <animateTransform
    attributeName="transform"
    type="translate"
    from="0,0"
    to="40,-30"
    dur="0.6s"
    fill="freeze"
  />
  <animate
    attributeName="opacity"
    from="1"
    to="0"
    dur="0.6s"
    fill="freeze"
  />
</circle>

<animateTransform><animate> を組み合わせると、移動と透明化を同時に走らせられる。CSS と違って座標系が SVG 内部の単位に素直に従うため、計算した通りに動く。

Vue からアニメーションを起動するには beginElement() を使う。

const svgRef = ref<SVGSVGElement | null>(null)

const triggerFirework = () => {
  const sparks = svgRef.value?.querySelectorAll('.spark animateTransform')
  sparks?.forEach(anim => (anim as SVGAnimateTransformElement).beginElement())
}

svgRef から querySelector で SMIL 要素を直接拾い、beginElement() を呼ぶ。仕訳プッシュのタイミングでこれを実行すると、花火が弾けた。


no09 の座標ミスを修正

no09(売掛金発生)は no01(設立出資)の鏡像パターンで作った。お金袋と商品を左右対称に配置するつもりだったが、座標を手計算した際にミスが入った。

要素誤った before 位置正しい before 位置
お金袋x ≈ 690x ≈ 824
リンゴx ≈ 464x ≈ 643

no01 の値を参照して上書きした。ブラウザで並べると、左右の動線がきれいに揃った。


no06 の SVG をファイルとして書き出す

no06 は Illustrator 側で手直しが必要になったため、Vue コンポーネントにインラインで書かれた SVG を単体ファイルとして抽出した。

TransactionNo06Animated.vue<svg> ブロックをそのまま切り出して memo/2026-05-05/transaction-no06-simple.svg に保存した。インライン SVG をコンポーネント外に出すだけなので、手順は単純だが、Illustrator が読めるように xmlns 属性が正しく入っているか確認した。


今日わかったこと

CSS transform は SVG 要素に対してブラウザが思った通りに動かさないことがある。同じ translate でも、<animateTransform> を使えば座標系が素直で安定する。

Nuxt のコンポーネント自動登録は、ディレクトリ構造がそのまま名前に乗る。深い階層に置いたコンポーネントを短い名前で使いたいなら pathPrefix: false を設定する。警告なしに無視されるので、表示されない原因として最初に疑うべき場所だった。