Las imágenes dinámicas de vue.js no funcionan

90

Tengo un caso en el que en mi Vue.jscon la webpackaplicación web, necesito mostrar imágenes dinámicas. Quiero mostrar imgdónde se almacenan los nombres de archivo de las imágenes en una variable. Esa variable es una computedpropiedad que devuelve una Vuexvariable de tienda, que se completa de forma asincrónica beforeMount.

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

Sin embargo, funciona perfectamente cuando solo lo hago:

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

Mi caso es similar a este violín , pero aquí funciona con la URL de img, pero en el mío con las rutas de archivo reales, no funciona.

¿Cuál debería ser la forma correcta de hacerlo?

Saurabh
fuente
1
resuelto `<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` este también resolvió el problema
Mohamed Raza

Respuestas:

98

Conseguí que esto funcione siguiendo el código

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

y en HTML:

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

Pero no estoy seguro de por qué mi enfoque anterior no funcionó.

Saurabh
fuente
7
Según nickmessing: "La expresión dentro de v-bind se ejecuta en tiempo de ejecución, el alias del paquete web se usa en tiempo de compilación". github.com/vuejs/vue-loader/issues/896
antoine
@Grigio tiene una buena mejora para esta respuesta: stackoverflow.com/a/47480286/5948587
samlandfried
1
El problema es que el camino no existe. Webpack compila toda la aplicación vue en un solo script (y las imágenes también se renombran normalmente, utilizando un hash del contenido). Al usar require.context, fuerza a que los archivos sean vistos por el paquete web y los resuelve en la imagen resultante. Compruebe el enlace de trabajo en el navegador y verá lo que quiero decir. Gran solucion
estani
¿Qué pasa si no quiero que mis imágenes estén en la carpeta de activos? ¿Qué pasa si solo existen en la carpeta pública del sitio web porque son subidos por usuarios del área de administración?
thinsoldier
hola, he intentado esto pero fallé, luego encontré otra solución que usa literales de plantilla. Podría funcionar y quiero compartir esto: stackoverflow.com/questions/57349167/…
lin
82

Aquí hay una abreviatura que utilizará webpack para que no tenga que usarla require.context.

HTML:

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

Método Vue:

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

Y encuentro que los primeros 2 párrafos aquí explican por qué esto funciona. bien.

Tenga en cuenta que es una buena idea colocar las imágenes de su mascota dentro de un subdirectorio, en lugar de colocarlas junto con todos sus otros recursos de imagen. Al igual que:./assets/pets/

Artur Grigio
fuente
`<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` este también resolvió el problema
Mohamed Raza
Esta fue la única solución funcional después de muchos intentos ..
makkus
38

Puedes probar la requirefunción. Me gusta esto:

<img :src="require(`@/xxx/${name}.png`)" alt class="icon" />
feng zhang
fuente
¿Por qué se @requiere ese símbolo?
daño
1
@El símbolo no es obligatorio, a menudo representa su srcdirectorio cuando se usa Resolve | webpack (vue-cli ya está configurando esto).
feng zhang
20

Hay otra forma de hacerlo agregando sus archivos de imagen a la carpeta pública en lugar de activos y accediendo a ellos como imágenes estáticas.

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

Aquí es donde debe colocar sus imágenes estáticas:

ingrese la descripción de la imagen aquí

Rukshan Dangalla
fuente
Esto funcionó para mí, excepto por la etiqueta alt, omití el v-bind
StefanBob
1
me salvó mucho dolor, recibí un error extraño: no se puede encontrar el módulo './undefined' usando require, gracias
drakkar
1
Creo que este es el camino a seguir, no la carpeta de activos.
mono
1
El requerimiento dinámico tampoco funcionó para mí en la última versión de Vue2
goodniceweb
8

Su mejor opción es usar un método simple para construir la cadena correcta para la imagen en el índice dado:

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

luego haz lo siguiente dentro de tu v-for:

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

Aquí está el JSFiddle (obviamente las imágenes no se muestran, así que puse la imagen al srclado de la imagen):

https://jsfiddle.net/q2rzssxr/

craig_h
fuente
De Verdad? Aquí hay un ejemplo con imágenes reales que parece funcionar bien: jsfiddle.net/q2rzssxr/1
craig_h
No estoy seguro de por qué, lo hice funcionar con el código que escribí en otra respuesta. Su
Saurabh
En mi caso, las fotos se están poblando de forma asincrónica usando la tienda Vuex, puede ser que tenga algo que hacer al respecto, intenté simularlo, pero no funcionó: jsfiddle.net/9a6Lg2vd/2
Saurabh
Mi caso es más parecido a este: jsfiddle.net/9a6Lg2vd/4 , pero en mis mascotas locales se completan los datos de una llamada ajax, pero las imágenes no se renderizan.
Saurabh
Esto también funciona: jsfiddle.net/9a6Lg2vd/5 , no estoy seguro de por qué no funciona con rutas de archivo.
Saurabh
5

También encontré este problema y parece que las dos respuestas más votadas funcionan, pero hay un pequeño problema, el paquete web arroja un error en la consola del navegador (Error: No se puede encontrar el módulo './undefined' en webpackContextResolve) que no es muy agradable.

Así que lo resolví de manera un poco diferente. Todo el problema con la variable dentro de la declaración require es que la declaración require se ejecuta durante la agrupación y la variable dentro de esa declaración aparece solo durante la ejecución de la aplicación en el navegador. Entonces, el paquete web ve la imagen requerida como indefinida de cualquier manera, ya que durante la compilación esa variable no existe.

Lo que hice fue colocar una imagen aleatoria en la declaración require y ocultar esa imagen en css, para que nadie la vea.

// 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}

La imagen viene como parte de la información de la base de datos a través de Vuex y se asigna al componente como un

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

Entonces, una vez que esta información está disponible, cambio la imagen inicial a la real

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

Aquí hay una respuesta muy simple. :RE

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

Puede usar try catch block para ayudar con las imágenes no encontradas

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
},
Gabriel Fernandez
fuente
2
<img src="../assets/graph_selected.svg"/>

Webpack resuelve la ruta estática como una dependencia del módulo a través del cargador. Pero para la ruta dinámica que necesita usar require para resolver la ruta. Luego puede cambiar entre imágenes usando una variable booleana y una expresión ternaria.

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

Y, por supuesto, alternar el valor del booleano a través de algún controlador de eventos.

Ron16
fuente
Gracias, esto funciona :src="require(../assets/category_avatar/baby_kids.jpeg)"
Mohamed Raza
0

Bueno, la mejor y más fácil forma que funcionó para mí fue esta de la cual estaba obteniendo datos de una API.

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

el método getPic toma un parámetro que es el nombre del archivo y devuelve la ruta absoluta del archivo, tal vez de su servidor con el nombre de archivo simple ...

aquí hay un ejemplo de un componente donde usé esto:

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

Encontré el mismo problema. Esto funcionó para mí al cambiar '../assets/' a './assets/'.

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

Intente importar una imagen como esta, porque Webpack debería conocer su dependencia

    <ul>
              <li v-for="social in socials" 
              v-bind:key="social.socialId"
              >

                <a :href="social.socialWeb" target="_blank">
                  <img class="img-fill" :id="social.socialId" :src="social.socialLink" :alt="social.socialName">
                </a>
              </li>

            </ul>

<script>
        import Image1 from '@/assets/images/social/twitter.svg'
        import Image2 from '@/assets/images/social/facebook.svg'
        import Image3 from '@/assets/images/social/rss.svg'
        export default {
          data(){
            return{
              socials:[{         
                   socialId:1,         
                   socialName: "twitter",
                   socialLink: Image1,
                   socialWeb: "http://twitter.com"
              },
      {
          socialId:2,
          socialName: "facebook",
           socialLink: Image2,
           socialWeb: "http://facebook.com"

      },
      {
          socialId:3,
          socialName: "rss",
           socialLink: Image3,
           socialWeb: "http://rss.com"
      }]

 </script>
perun10
fuente