Dynamiczne obrazy Vue.js nie działają

90

Mam przypadek, gdy w moim Vue.jsz webpackaplikacji internetowej, muszę wyświetlania dynamicznych obrazów. Chcę pokazać, imggdzie nazwa pliku obrazów jest przechowywana w zmiennej. Ta zmienna jest computedwłaściwością, która zwraca Vuexzmienną magazynu, która jest wypełniana asynchronicznie beforeMount.

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

Jednak działa idealnie, gdy po prostu robię:

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

Mój przypadek jest podobny do tego skrzypiec , ale tutaj działa z img URL, ale w moim z rzeczywistymi ścieżkami plików nie działa.

Jaki powinien być właściwy sposób, aby to zrobić?

Saurabh
źródło
1
rozwiązane `<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` ten również rozwiązał problem
Mohamed Raza

Odpowiedzi:

98

Mam to działające, postępując zgodnie z kodem

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

i w HTML:

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

Ale nie jestem pewien, dlaczego moje wcześniejsze podejście nie zadziałało.

Saurabh
źródło
7
Zgodnie z nickmessingiem: "Wyrażenie wewnątrz v-bind jest wykonywane w czasie wykonywania, aliasy webpacka w czasie kompilacji." github.com/vuejs/vue-loader/issues/896
antoine
@Grigio ma niezłe ulepszenie tej odpowiedzi: stackoverflow.com/a/47480286/5948587
samlandfried,
1
Problem polegał na tym, że ścieżka nie istnieje. Cała aplikacja vue jest kompilowana przez webpack do jednego skryptu (a nazwy obrazów są również normalnie zmieniane, używając skrótu zawartości). Używając require.context, wymuszasz, aby pliki były widoczne przez webpack i rozwiązywały do ​​wynikowego obrazu. Sprawdź działający link w przeglądarce, a zobaczysz o co mi chodzi. Świetne rozwiązanie.
estani
A jeśli nie chcę, aby moje obrazy były w folderze zasobów? A co jeśli istnieją tylko w folderze publicznym witryny, ponieważ zostały przesłane przez użytkowników obszaru administracyjnego?
Thinsoldier
witam, próbowałem tego, ale nie udało mi się, potem znalazłem inne rozwiązanie, które używa literałów szablonu. To mogłoby zadziałać i chcę się tym podzielić: stackoverflow.com/questions/57349167/…
lin
82

Oto skrót, którego użyje webpack, więc nie musisz go używać require.context.

HTML:

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

Metoda Vue:

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

I stwierdzam, że pierwsze 2 akapity tutaj wyjaśniają, dlaczego to działa? dobrze.

Pamiętaj, że dobrym pomysłem jest umieszczenie zdjęć zwierzaków w podkatalogu, zamiast wrzucać je do wszystkich innych zasobów graficznych. Tak jak to:./assets/pets/

Artur Grigio
źródło
`<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` ten również rozwiązał problem
Mohamed Raza
To było jedyne działające rozwiązanie po wielu próbach ...
makkus
38

Możesz wypróbować tę requirefunkcję. lubię to:

<img :src="require(`@/xxx/${name}.png`)" alt class="icon" />
feng zhang
źródło
Dlaczego ten @symbol jest wymagany?
szkoda
1
@symbol nie jest wymagany, często reprezentuje twój srcdir podczas używania Resolve | webpack (vue-cli już to konfiguruje).
feng zhang
20

Można to zrobić w inny sposób, dodając pliki obrazów do folderu publicznego zamiast do zasobów i uzyskując do nich dostęp jako obrazy statyczne.

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

Tutaj musisz umieścić swoje statyczne obrazy:

wprowadź opis obrazu tutaj

Rukshan Dangalla
źródło
To zadziałało dla mnie z wyjątkiem tagu alt, który pominąłem v-bind
StefanBob
1
zaoszczędził mi wiele bólu, mam dziwny błąd: Nie można znaleźć modułu './undefined' używając wymagania, dzięki
drakkar
1
Myślę, że to jest droga, a nie folder zasobów.
jukenduit
1
dynamiczne wymaganie też nie zadziałało w najnowszym Vue2
goodniceweb
8

Najlepiej jest po prostu użyć prostej metody do zbudowania prawidłowego ciągu dla obrazu o podanym indeksie:

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

następnie wykonaj następujące czynności w swoim v-for:

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

Oto JSFiddle (oczywiście obrazy się nie pokazują, więc umieściłem obraz srcobok obrazu):

https://jsfiddle.net/q2rzssxr/

craig_h
źródło
Naprawdę? Oto przykład z prawdziwymi obrazami, które wydają się działać dobrze: jsfiddle.net/q2rzssxr/1
craig_h
Nie wiem dlaczego, mam to działające według kodu, który napisałem w innej odpowiedzi. Twój przykład działa nawet bez tej funkcji, patrz tutaj: jsfiddle.net/9a6Lg2vd/1
Saurabh
W moim przypadku zdjęcia są wypełniane asynchronicznie za pomocą sklepu Vuex, może to ma coś wspólnego z tym, próbowałem to zasymulować, ale nie zadziałało: jsfiddle.net/9a6Lg2vd/2
Saurabh
Mój przypadek jest bardziej podobny do tego: jsfiddle.net/9a6Lg2vd/4 , ale u moich lokalnych zwierząt domowych dane są wypełniane przez wywołanie Ajax , ale obrazy nie są renderowane.
Saurabh
To również działa: jsfiddle.net/9a6Lg2vd/5 , nie jestem pewien, dlaczego nie działa ze ścieżkami plików.
Saurabh
5

Trafiłem też na ten problem i wygląda na to, że obie większość odpowiedzi działają, ale jest mały problem, webpack wyrzuca błąd do konsoli przeglądarki (Error: Cannot find module './undefined' at webpackContextResolve), co nie jest zbyt miłe.

Więc rozwiązałem to trochę inaczej. Cały problem ze zmienną wewnątrz instrukcji require polega na tym, że instrukcja require jest wykonywana podczas pakowania, a zmienna wewnątrz tej instrukcji pojawia się tylko podczas wykonywania aplikacji w przeglądarce. Tak więc webpack widzi wymagany obraz jako niezdefiniowany w obu przypadkach, ponieważ podczas kompilacji ta zmienna nie istnieje.

To, co zrobiłem, to umieszczenie losowego obrazu w instrukcji wymagania i ukrycie tego obrazu w css, aby nikt go nie widział.

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

Obraz jest częścią informacji z bazy danych za pośrednictwem Vuex i jest mapowany na komponent jako obliczony

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

Kiedy te informacje są dostępne, zamieniam obraz początkowy na prawdziwy

watch: {
  user(userData) {
    this.userAvatar = require(`@/assets/${userData.avatar}`);
    this.hidden = false;
  }
}
Alonad
źródło
4

Oto bardzo prosta odpowiedź. :RE

<div class="col-lg-2" v-for="pic in pics">
   <img :src="`../assets/${pic}.png`" :alt="pic">
</div>
Diament
źródło
3

Możesz użyć bloku try catch, aby pomóc w znalezieniu obrazów

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
źródło
2
<img src="../assets/graph_selected.svg"/>

Ścieżka statyczna jest rozpoznawana przez Webpack jako zależność modułu przez program ładujący. Ale w przypadku ścieżki dynamicznej musisz użyć wymagania do rozwiązania ścieżki. Następnie możesz przełączać się między obrazami, używając zmiennej boolowskiej i wyrażenia trójskładnikowego.

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

I oczywiście przełączaj wartość boolowską za pomocą jakiejś obsługi zdarzeń.

Ron16
źródło
Dziękuję, to działa :src="require(../assets/category_avatar/baby_kids.jpeg)"
Mohamed Raza
0

cóż, najlepszym i najłatwiejszym sposobem, który działał dla mnie, był ten, w którym pobierałem dane z interfejsu API.

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

metoda getPic przyjmuje jeden parametr, który jest nazwą pliku i zwraca bezwzględną ścieżkę do pliku, być może z twojego serwera, z prostą nazwą pliku ...

oto przykład komponentu, w którym użyłem tego:

<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>
user8453321
źródło
0

Napotkałem ten sam problem. U mnie to zadziałało, zmieniając „../assets/” na „./assets/”.

 <img v-bind:src="'./assets/' + pic + '.png'" v-bind:alt="pic">
Bex
źródło
-1

Spróbuj zaimportować obraz w ten sposób, ponieważ Webpack powinien wiedzieć o jego zależności

    <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
źródło