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?


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ó.


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/


`<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" />

¿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í


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/


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

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>

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

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.


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>

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

-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>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.