Le immagini dinamiche di Vue.js non funzionano


100

Ho un caso in cui nel mio Vue.jscon webpackweb app, ho bisogno di visualizzare immagini dinamiche. Voglio mostrare imgdove sono memorizzati i nomi dei file delle immagini in una variabile. Quella variabile è una computedproprietà che restituisce una Vuexvariabile negozio, che viene popolata in modo asincrono su beforeMount.

<div class="col-lg-2" v-for="pic in pics">
   <img v-bind:src="'../assets/' + pic + '.png'" v-bind:alt="pic">
</div>

Tuttavia funziona perfettamente quando faccio solo:

<img src="../assets/dog.png" alt="dog">

Il mio caso è simile a questo violino , ma qui funziona con img URL, ma nel mio con percorsi di file effettivi, non funziona.

Quale dovrebbe essere il modo corretto per farlo?


1
risolto "<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>" anche questo ha risolto il problema
Mohamed Raza

Risposte:


104

Ho ottenuto questo funzionamento seguendo il codice

  getImgUrl(pet) {
    var images = require.context('../assets/', false, /\.png$/)
    return images('./' + pet + ".png")
  }

e in HTML:

<div class="col-lg-2" v-for="pic in pics">
   <img :src="getImgUrl(pic)" v-bind:alt="pic">
</div>

Ma non sono sicuro del motivo per cui il mio approccio precedente non ha funzionato.


7
Secondo nickmessing: "L'espressione all'interno di v-bind viene eseguita in fase di esecuzione, gli alias webpack in fase di compilazione." github.com/vuejs/vue-loader/issues/896
antoine

@Grigio ha un bel miglioramento a questa risposta: stackoverflow.com/a/47480286/5948587
samlandfried

1
Il problema era che il percorso non esiste. L'intera app vue viene compilata da webpack in un unico script (e anche le immagini vengono rinominate normalmente, utilizzando un hash dei contenuti). Usando require.context, forzi i file a essere visti da webpack e risolti nell'immagine risultante. Controlla il collegamento funzionante nel browser e vedrai cosa intendo. Ottima soluzione.
estani

E se non desidero che le mie immagini si trovino nella cartella delle risorse? E se esistono solo nella cartella pubblica del sito Web perché vengono caricati dagli utenti dell'area di amministrazione?
Thinsoldier

ciao, ho provato questo ma non è riuscito, quindi ho trovato un'altra soluzione che utilizza i letterali modello. Potrebbe funzionare e voglio condividere questo: stackoverflow.com/questions/57349167/…
lin

87

Ecco una scorciatoia che webpack userà quindi non devi usare require.context.

HTML:

<div class="col-lg-2" v-for="pic in pics">
    <img :src="getImgUrl(pic)" v-bind:alt="pic">
</div>

Metodo Vue:

getImgUrl(pic) {
    return require('../assets/'+pic)
}

E trovo che i primi 2 paragrafi qui spieghino perché funziona? bene.

Tieni presente che è una buona idea inserire le foto dei tuoi animali domestici in una sottodirectory, invece di inserirle insieme a tutte le altre risorse di immagine. Così:./assets/pets/


"<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>" anche questo ha risolto il problema
Mohamed Raza

Questa era l'unica soluzione funzionante dopo un sacco di tentativi ..
makkus

45

Puoi provare la requirefunzione. come questo:

<img :src="require(`@/xxx/${name}.png`)" alt class="icon" />

Perché è @richiesto quel simbolo?
danno il

1
@Il simbolo non è richiesto, rappresenta offten la tua directory srcquando usi Risolvi | webpack (vue-cli lo sta già configurando).
feng zhang

21

C'è un altro modo per farlo aggiungendo i file di immagine alla cartella pubblica invece delle risorse e accedendo a quelli come immagini statiche.

<img :src="'/img/' + pic + '.png'" v-bind:alt="pic" >

Qui è dove devi mettere le tue immagini statiche:

inserisci qui la descrizione dell'immagine


Questo ha funzionato per me tranne per il tag alt che ho omesso il v-bind
StefanBob

1
mi ha salvato un sacco di dolore, ho ricevuto uno strano errore: impossibile trovare il modulo "./undefined" utilizzando require, grazie
drakkar

1
Penso che questa sia la strada da percorrere, non la cartella delle risorse.
jukenduit

1
Il requisito dinamico non ha funzionato anche per me nell'ultimo Vue2
goodniceweb

8

La soluzione migliore è utilizzare solo un metodo semplice per costruire la stringa corretta per l'immagine all'indice dato:

methods: {
  getPic(index) {
    return '../assets/' + this.pics[index] + '.png';
  }
}

quindi fai quanto segue all'interno del tuo v-for:

<div class="col-lg-2" v-for="(pic, index) in pics">
   <img :src="getPic(index)" v-bind:alt="pic">
</div>

Ecco il JSFiddle (ovviamente le immagini non vengono visualizzate, quindi ho messo l'immagine srcaccanto all'immagine):

https://jsfiddle.net/q2rzssxr/


Veramente? Ecco un esempio con immagini reali che sembrano funzionare bene: jsfiddle.net/q2rzssxr/1
craig_h

Non sono sicuro del perché, ho funzionato con il codice che ho scritto in un'altra risposta. L'esempio funziona anche senza questa funzione, vedi qui: jsfiddle.net/9a6Lg2vd/1
Saurabh

Nel mio caso, le foto vengono popolate in modo asincrono utilizzando il negozio Vuex, potrebbe essere che abbia qualcosa da fare al riguardo, ho provato a simularlo, ma non ha funzionato: jsfiddle.net/9a6Lg2vd/2
Saurabh

Il mio caso è più simile a questo: jsfiddle.net/9a6Lg2vd/4 , ma nei miei animali domestici i dati vengono popolati da una chiamata ajax, ma le immagini non vengono visualizzate.
Saurabh

Funziona anche: jsfiddle.net/9a6Lg2vd/5 , non so perché non funziona con i percorsi dei file.
Saurabh

6

Ho anche riscontrato questo problema e sembra che entrambe le risposte più votate funzionino, ma c'è un piccolo problema, webpack genera un errore nella console del browser (Errore: Impossibile trovare il modulo './undefined' su webpackContextResolve) che non è molto carino.

Quindi l'ho risolto in modo leggermente diverso. L'intero problema con la variabile all'interno dell'istruzione require è che l'istruzione require viene eseguita durante il raggruppamento e la variabile all'interno di tale istruzione appare solo durante l'esecuzione dell'app nel browser. Quindi webpack vede l'immagine richiesta come indefinita in entrambi i casi, poiché durante la compilazione quella variabile non esiste.

Quello che ho fatto è stato inserire un'immagine casuale nella dichiarazione require e nascondere quell'immagine in CSS, in modo che nessuno la vedesse.

// template
<img class="user-image-svg" :class="[this.hidden? 'hidden' : '']" :src="userAvatar" alt />

//js
data() {
  return {
    userAvatar: require('@/assets/avatar1.svg'),
    hidden: true
  }
}

//css
.hidden {display: none}

L'immagine arriva come parte delle informazioni dal database tramite Vuex ed è mappata al componente come un computer

computed: {
  user() {
    return this.$store.state.auth.user;
  }
}

Quindi, una volta che queste informazioni sono disponibili, scambio l'immagine iniziale con quella reale

watch: {
  user(userData) {
    this.userAvatar = require(`@/assets/${userData.avatar}`);
    this.hidden = false;
  }
}

4

Ecco una risposta molto semplice. : D

<div class="col-lg-2" v-for="pic in pics">
   <img :src="`../assets/${pic}.png`" :alt="pic">
</div>

3

Puoi usare il blocco try catch per aiutare con le immagini non trovate

getProductImage(id) {
          var images = require.context('@/assets/', false, /\.jpg$/)
          let productImage = ''
          try {
            productImage = images(`./product${id}.jpg`)
          } catch (error) {
            productImage = images(`./no_image.jpg`)
          }
          return productImage
},

2
<img src="../assets/graph_selected.svg"/>

Il percorso statico viene risolto da Webpack come dipendenza del modulo tramite il caricatore. Ma per il percorso dinamico è necessario utilizzare require per risolvere il percorso. È quindi possibile passare da un'immagine all'altra utilizzando una variabile booleana e un'espressione ternaria.

<img :src="this.graph ? require( `../assets/graph_selected.svg`) 
: require( `../assets/graph_unselected.svg`) " alt="">

E ovviamente cambia il valore del booleano tramite un gestore di eventi.


Grazie, funziona :src="require(../assets/category_avatar/baby_kids.jpeg)"
Mohamed Raza

2

Vue.js utilizza vue-loader, un caricatore per WebPack che è impostato per riscrivere / convertire i percorsi in fase di compilazione, in modo da consentirti di non preoccuparti dei percorsi statici che differirebbero tra le distribuzioni (locale, dev, una piattaforma di hosting o l'altra) , consentendo di utilizzare i percorsi del file system locale relativi . Aggiunge anche altri vantaggi come la memorizzazione nella cache delle risorse e il controllo delle versioni (probabilmente puoi vederlo controllando l' srcURL effettivo generato).

Quindi avere un src che sarebbe normalmente gestito da vue-loader/ WebPack impostato su un'espressione dinamica, valutata in fase di esecuzione, aggirerà questo meccanismo e l'URL dinamico generato non sarà valido nel contesto della distribuzione effettiva (a meno che non sia completamente qualificato, questa è un'eccezione ).

Se invece utilizzassi una requirechiamata di funzione nell'espressione dinamica, vue-loader/ WebPack la vedrà e applicherà la solita magia.

Ad esempio, questo non funzionerebbe:

<img alt="Logo" :src="logo" />
computed: {
    logo() {
        return this.colorMode === 'dark'
               ? './assets/logo-dark.png'
               : './assets/logo-white.png';
    }
}

Mentre questo funzionerebbe:

<img alt="Logo" :src="logo" />
computed: {
    logo() {
        return this.colorMode === 'dark'
               ? require('./assets/logo-dark.png')
               : require('./assets/logo-white.png');
    }
}

L'ho appena scoperto da solo. Mi ci è voluta un'ora ma ... vivi, impari, vero? 😊


0

beh, il modo migliore e più semplice che ha funzionato per me era questo di cui stavo recuperando i dati da un'API ..

methods: {
       getPic(index) {
    return this.data_response.user_Image_path + index;
  }
 }

il metodo getPic prende un parametro che è il nome del file e restituisce il percorso assoluto del file magari dal tuo server con il nome del file semplice ...

ecco un esempio di un componente in cui ho usato questo:

<template>
    <div class="view-post">
        <div class="container">
     <div class="form-group">
             <label for=""></label>
             <input type="text" class="form-control" name="" id="" aria-describedby="helpId" placeholder="search here">
             <small id="helpId" class="form-text user-search text-muted">search for a user here</small>
           </div>
           <table class="table table-striped ">
               <thead>
                   <tr>
                       <th>name</th>
                       <th>email</th>
                       <th>age</th>
                       <th>photo</th>
                   </tr>
                   </thead>
                   <tbody>
                       <tr v-bind:key="user_data_get.id"  v-for="user_data_get in data_response.data">
                           <td scope="row">{{ user_data_get.username }}</td>
                           <td>{{ user_data_get.email }}</td>
                           <td>{{ user_data_get.userage }}</td>
                           <td><img :src="getPic(user_data_get.image)"  clas="img_resize" style="height:50px;width:50px;"/></td>
                       </tr>

                   </tbody>
           </table>
        </div>

    </div>
</template>

<script>
import axios from 'axios';
export default {
     name: 'view',
  components: {

  },
  props:["url"],
 data() {
     return {
         data_response:"",
         image_path:"",
     }
 },
 methods: {
       getPic(index) {
    return this.data_response.user_Image_path + index;
  }
 },
 created() {
     const res_data = axios({
    method: 'post',
    url: this.url.link+"/view",
   headers:{
     'Authorization': this.url.headers.Authorization,
     'content-type':this.url.headers.type,
   }
    })
    .then((response)=> {
        //handle success
      this.data_response = response.data;
      this.image_path = this.data_response.user_Image_path;
       console.log(this.data_response.data)
    })
    .catch(function (response) {
        //handle error
        console.log(response);
    });
 },
}
</script>


<style scoped>

</style>

0

Ho riscontrato lo stesso problema. Questo ha funzionato per me cambiando "../assets/" in "./assets/".

 <img v-bind:src="'./assets/' + pic + '.png'" v-bind:alt="pic">

0

Ho provato tutte le risposte qui, ma quello che ha funzionato per me su Vue2 è così.

<div class="col-lg-2" v-for="pic in pics">
   <img :src="require(`../assets/${pic.imagePath}.png`)" :alt="pic.picName">
</div>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.