Динамические изображения Vue.js не работают

90

У меня есть случай , когда в моем Vue.jsс webpackвеб - приложение, мне нужно , чтобы отобразить динамические изображения. Я хочу показать, imgгде в переменной хранятся имена файлов изображений. Эта переменная является computedсвойством, которое возвращает Vuexпеременную хранилища, которая заполняется асинхронно beforeMount.

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

Однако он отлично работает, когда я просто делаю:

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

Мой случай похож на эту скрипку , но здесь он работает с URL-адресом img, но в моем случае с фактическими путями к файлам это не работает.

Каким должен быть правильный способ сделать это?

Саураб
источник
1
решено `<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` этот также решил проблему
Мохамед Раза

Ответы:

98

Я получил это с помощью следующего кода

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

и в HTML:

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

Но не уверен, почему мой предыдущий подход не сработал.

Саураб
источник
7
Согласно nickmessing: «Выражение внутри v-bind выполняется во время выполнения, а псевдонимы webpack - во время компиляции». github.com/vuejs/vue-loader/issues/896
антуан
У @Grigio есть отличное улучшение этого ответа: stackoverflow.com/a/47480286/5948587
samlandfried
1
Проблема была в том, что пути не существует. Все приложение vue компилируется с помощью webpack в один скрипт (и изображения также обычно переименовываются, используя хэш содержимого). Используя require.context, вы заставляете файлы отображаться в webpack и преобразовывать их в полученное изображение. Проверьте рабочую ссылку в браузере, и вы поймете, что я имею в виду. Отличное решение.
estani
Что делать, если я не хочу, чтобы мои изображения находились в папке с ресурсами? Что, если они существуют только в общей папке веб-сайта, потому что загружены пользователями из административной области?
thinsoldier
привет, я пробовал это, но потерпел неудачу, затем я нашел другое решение, использующее литералы шаблонов. Это может сработать, и я хочу поделиться этим: stackoverflow.com/questions/57349167/…
lin
82

Вот сокращение, которое будет использовать webpack, поэтому вам не нужно его использовать require.context.

HTML:

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

Метод Vue:

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

И я считаю , что первые 2 параграфы здесь объяснить , почему это работает? Что ж.

Обратите внимание, что лучше всего поместить фотографии своих питомцев в подкаталог, а не вставлять их вместе со всеми остальными изображениями. Вот так:./assets/pets/

Артур Гриджио
источник
`<v-img: src =" require ( @/assets/+ items.image) "height =" 200px "> </v-img>` этот тоже решил проблему
Мохамед Раза
Это было единственное рабочее решение после долгих попыток ..
makkus
38

Вы можете попробовать эту requireфункцию. как это:

<img :src="require(`@/xxx/${name}.png`)" alt class="icon" />
Фэн Чжан
источник
Зачем @нужен этот символ?
вред
1
@символ не требуется, он часто представляет ваш srcкаталог при использовании Resolve | webpack (vue-cli уже настроил это.).
feng zhang
20

Есть другой способ сделать это, добавив файлы изображений в общую папку вместо ресурсов и получив доступ к ним как к статическим изображениям.

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

Здесь вам нужно разместить статические изображения:

введите описание изображения здесь

Рукшан Дангалла
источник
Это сработало для меня, за исключением тега alt, который я пропустил v-bind
StefanBob
1
избавил меня от боли, у меня возникла странная ошибка: не могу найти модуль './undefined' с помощью require, спасибо
drakkar
1
Я думаю, что это правильный путь, а не папка с ресурсами.
Jukenduit
1
dynamic require не работал у меня в последней версии Vue2
goodniceweb
8

Лучше всего использовать простой метод для создания правильной строки для изображения по заданному индексу:

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

затем сделайте следующее внутри v-for:

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

Вот JSFiddle (очевидно, изображения не отображаются, поэтому я поместил изображение srcрядом с изображением):

https://jsfiddle.net/q2rzssxr/

craig_h
источник
В самом деле? Вот пример с реальными изображениями, которые, кажется, работают нормально: jsfiddle.net/q2rzssxr/1
craig_h 08
Не уверен, почему, я заставил его работать с кодом, который я написал в другом ответе. Вы пример работает даже без этой функции, смотрите здесь: jsfiddle.net/9a6Lg2vd/1
Саурабй
В моем случае, фото заселяется асинхронно с помощью Vuex магазин, может быть, есть что - то с этим делать, я пытался имитировать его, но не сделал работу: jsfiddle.net/9a6Lg2vd/2
Saurabh
Мой случай больше похож на этот: jsfiddle.net/9a6Lg2vd/4 , но в моих локальных питомцах данные заполняются из вызова ajax, но изображения не отображаются.
Saurabh
Это также работает: jsfiddle.net/9a6Lg2vd/5 , не уверен, почему он не работает с путями к файлам.
Saurabh
5

Я также столкнулся с этой проблемой, и кажется, что оба наиболее популярных ответа работают, но есть небольшая проблема, webpack выдает ошибку в консоли браузера (Ошибка: не удается найти модуль './undefined' в webpackContextResolve), что не очень приятно.

Так что я решил немного иначе. Вся проблема с переменной внутри оператора require заключается в том, что оператор require выполняется во время связывания, а переменная внутри этого оператора появляется только во время выполнения приложения в браузере. Таким образом, webpack в любом случае видит необходимое изображение как неопределенное, так как во время компиляции эта переменная не существует.

Что я сделал, так это поместил случайное изображение в оператор require и скрыл это изображение в css, чтобы его никто не увидел.

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

Изображение поступает как часть информации из базы данных через Vuex и отображается на компонент как вычисленный

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

Итак, как только эта информация станет доступной, я заменяю исходное изображение на реальное.

watch: {
  user(userData) {
    this.userAvatar = require(`@/assets/${userData.avatar}`);
    this.hidden = false;
  }
}
Алонад
источник
4

Вот очень простой ответ. : D

<div class="col-lg-2" v-for="pic in pics">
   <img :src="`../assets/${pic}.png`" :alt="pic">
</div>
Алмаз
источник
3

Вы можете использовать блок try catch, чтобы помочь с не найденными изображениями

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 как зависимость модуля через загрузчик. Но для динамического пути вам нужно использовать require для разрешения пути. Затем вы можете переключаться между изображениями, используя логическую переменную и тройное выражение.

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

И, конечно же, переключите значение логического значения через какой-нибудь обработчик событий.

Ron16
источник
Спасибо, это работает :src="require(../assets/category_avatar/baby_kids.jpeg)"
Мохамед Раза
0

ну, лучший и самый простой способ, который сработал для меня, был тот, из которого я извлекал данные из API.

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

метод getPic принимает один параметр, который является именем файла, и возвращает абсолютный путь к файлу, возможно, с вашего сервера с простым именем файла ...

вот пример компонента, в котором я это использовал:

<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
источник
0

Я столкнулся с той же проблемой. Это сработало для меня, изменив "../assets/" на "./assets/".

 <img v-bind:src="'./assets/' + pic + '.png'" v-bind:alt="pic">
Bex
источник
-1

Попробуйте импортировать изображение таким образом, потому что Webpack должен знать о его зависимости

    <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>
перун10
источник