Vueのassetsフォルダに入れたimg画像ファイルを表示する方法と画像パスについて

2021年6月19日Vue.js

Vueのassetsフォルダに入れたimg画像ファイルを表示する方法をまとめました。
また、画像パスの@や~@の意味を解説しています。
最後に画像がうまく表示されない場合の原因とその対処方法を紹介しています。

Vueのassetsフォルダに入れたimg画像ファイルを使用する方法

まず、Nust.jsで使う場合、こちらの記事がとても参考になります。
assetsフォルダではなくstaticにいれるなどした画像の配置場所で指定方法が異なるので注意が必要です。

フォルダ構成


src/
|- assets/
|  |- img/
|  |  |- img1.jpg
|  |  |- img2.jpg
|  |  |- img3.jpg
|  |  |- img4.jpg
|  |  |- img5.jpg
|  ...
|
|- main.js
|- App.vue

srcフォルダのassetsフォルダにimgフォルダを作成して、その中に画像ファイルを格納しているとします。

imgタグの静的なsrc属性で指定

<template>
<header class="header">
  <div class="header__logo-box">
    <img src="@/assets/img/img1.jpg" alt="Logo" class="header__logo">
    <img src="~@/assets/img/img1.jpg" alt="Logo" class="header__logo">
    <img src="../assets/img/img1.jpg" alt="Logo" class="header__logo">
  </div>
</header>
</template>

上の3通りどれでも正常に動作します。

@や~@の意味

@ はプロジェクトの src フォルダを指すエイリアスで、Vue CLI プロジェクトでデフォルトで設定されています。
~@ は、Webpack の loader が使うエイリアス表記で、CSS や Sass ファイルでパス解決に使われます。

imgタグの動的なsrc属性をscriptで変数を作成して指定

<template>
<header class="header">
  <div class="header__logo-box">
    <img :src="img1" alt="Logo" class="header__logo">
    <img :src="img2" alt="Logo" class="header__logo">
    <img :src="img3" alt="Logo" class="header__logo">
  </div>
</header>
</template>

上のようにimg1からimg3までの変数を使用して、v-bindで動的にしたsrc属性に変数を使っって画像を指定します。

上のケースで、srciptで変数を作成する場合、うまく動作するケースとしないケースが下の通りです。

<script>
import { ref } from 'vue'
export default {
  setup() {
    const img1 = ref()
    const img2 = ref()
    const img3 = ref()

  // 動かない
    // img1.value = '../assets/img/img/img1'
    // img2.value = '@/assets/img/img/img1'
    // img3.value = '~@/assets/img/img/img1'

  // 動く
    img1.value = require('../assets/img/img/img1')
    img2.value = require('@/assets/img/img/img1')

  // 動かない
    // img3.value = require('~@/assets/img/img/img1')

    return {
      img1,
      img2,
      img3,
    }
  },
}</script>

requireをつけないと動作しません。
また、requireをつけてもパスが~@の場合は動作しません。

変数を使わずtemplateでimgタグの動的なsrc属性に直接指定

変数を使わずimgタグの動的なsrc属性に直接指定する場合も上と同様です。

<template>
<header class="header">
  <div class="header__logo-box">
  <!-- うまく動作する -->
    <img :src="require('../assets/img/img1.jpg')" alt="Logo" class="header__logo">
    <img :src="require('@/assets/img/img1.jpg')" alt="Logo" class="header__logo">
  <!-- 動作しない -->
    <!-- <img :src="require('~@/assets/img/img1.jpg')" alt="Logo" class="header__logo"> -->
  </div>
</header>
</template>

cssでbackground-imageとして指定

上記のheaderクラスにbackground-imageで背景画像を挿入します。

.header {
    height: 85vh;
  // うまく動作する
    background-image: url(../assets/img/hero-small.jpg);
    background-image: url(~@/assets/img/hero-small.jpg);
  // うまく動作しない
    // background-image: url(@/assets/img/hero-small.jpg);
}

その場合、今度は@はうまく動作せず、その他の方法でうまく動作します。

Vue 3の画像パスに関する注意点

Vue 3 では、静的な画像を使う場合に、require() や import を使う方法が推奨されています。~@ は一般的に CSS で使用されますが、JavaScript やテンプレート内では不要です。
require() はビルド時に画像ファイルを解決するために必要な場合があります。
静的な画像を参照するには、以下のように記述します。

<img src="@/assets/img/img1.jpg" alt="Logo" />
<img :src="require('@/assets/img/img1.jpg')" alt="Logo" />
<img :src="new URL('@/assets/img/img1.jpg', import.meta.url).href" alt="Logo" />

動的に設定する場合

<script setup>
import { ref } from 'vue';

const img1 = ref(require('@/assets/img/img1.jpg'));
const img2 = ref(new URL('@/assets/img/img2.jpg', import.meta.url).href);
</script>

<template>
  <img :src="img1" alt="Logo" />
  <img :src="img2" alt="Logo" />
</template>

require() と import.meta.url の説明

Vue 3 の場合、require() は動作するものの、ES Modules を採用するプロジェクトでは import.meta.url を使うのがモダンな方法です。
require() は CommonJS の仕様であり、将来的に非推奨となる可能性があります。
import.meta.url を使うと、モジュールのURLを基準に画像パスを解決できます。

const imgUrl = new URL('@/assets/img/img1.jpg', import.meta.url).href;

画像が正しく表示されないとき

../assets/img/img1.jpg が動かない場合

相対パスで指定しても、ビルド時にWebpackが適切に画像を解決できないためと考えられます。
解決策としては、上で説明しているrequire() や import.meta.url を使う方法です。

~@/assets/img/img1.jpg が動かない場合

JavaScript 内では ~ は CSS 用であり、テンプレートやスクリプト内では無効となります。

Vue.js

Posted by devsakaso