รูปภาพไดนามิก Vue.js ไม่ทำงาน


99

ผมมีกรณีที่ในของฉันVue.jsกับwebpackapp เว็บฉันต้องแสดงภาพแบบไดนามิก ฉันต้องการแสดงimgตำแหน่งที่เก็บชื่อไฟล์ของรูปภาพในตัวแปร ตัวแปรที่เป็นcomputedสถานที่ให้บริการซึ่งจะกลับตัวแปรเก็บซึ่งจะถูกถ่ายทอดสดในประชากรVuexbeforeMount

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

กรณีของฉันคล้ายกับซอนี้แต่ที่นี่ใช้งานได้กับ img URL แต่ในของฉันที่มีเส้นทางไฟล์จริงมันใช้ไม่ได้

วิธีที่ถูกต้องควรทำอย่างไร?


1
แก้ไข `<v-img: src =" ต้อง ( @/assets/+ items.image) "height =" 200px "> </v-img>` อันนี้ก็แก้ปัญหาได้เช่นกัน
Mohamed Raza

คำตอบ:


104

ฉันทำงานได้ตามรหัสต่อไปนี้

  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

จะเกิดอะไรขึ้นถ้าฉันไม่ต้องการให้รูปภาพของฉันอยู่ในโฟลเดอร์ assets จะเป็นอย่างไรหากมีอยู่ในโฟลเดอร์สาธารณะของเว็บไซต์เนื่องจากผู้ใช้พื้นที่ผู้ดูแลระบบอัปโหลด
thinsoldier

สวัสดีฉันได้ลองแล้ว แต่ล้มเหลวจากนั้นฉันพบวิธีแก้ปัญหาอื่นที่ใช้ตัวอักษรเทมเพลต มันใช้งานได้และฉันต้องการแบ่งปันสิ่งนี้: stackoverflow.com/questions/57349167/…
lin

86

นี่คือชวเลขที่ 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 =" ต้องใช้ ( @/assets/+ items.image) "height =" 200px "> </v-img>" อันนี้แก้ปัญหาได้เช่นกัน
Mohamed Raza

นี่เป็นวิธีแก้ปัญหาเดียวที่ใช้ได้ผลหลังจากพยายามมามาก ..
makkus

45

คุณสามารถลองใช้requireฟังก์ชัน แบบนี้:

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

ทำไม@ต้องใช้สัญลักษณ์นั้น?
อันตราย

1
@ไม่จำเป็นต้องใช้สัญลักษณ์มันแสดงถึงsrcdir ของคุณเมื่อใช้Resolve | webpack (vue-cli กำหนดค่านี้อยู่แล้ว)
feng zhang

21

มีอีกวิธีหนึ่งในการเพิ่มไฟล์รูปภาพของคุณไปยังโฟลเดอร์สาธารณะแทนที่จะเป็นเนื้อหาและเข้าถึงไฟล์เหล่านั้นเป็นภาพนิ่ง

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

นี่คือที่ที่คุณต้องใส่ภาพนิ่งของคุณ:

ป้อนคำอธิบายภาพที่นี่


สิ่งนี้ใช้ได้ผลสำหรับฉันยกเว้นแท็ก alt ฉันละเว้น v-bind
StefanBob

1
ช่วยให้ฉันเจ็บปวดมากฉันได้รับข้อผิดพลาดแปลก ๆ : ไม่พบโมดูล './undefined' โดยใช้ต้องขอบคุณ
drakkar

1
ฉันคิดว่านี่เป็นวิธีที่จะไปไม่ใช่โฟลเดอร์เนื้อหา
jukenduit

1
ต้องการแบบไดนามิกก็ใช้ไม่ได้สำหรับฉันเช่นกันใน 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/


จริงๆ? นี่คือตัวอย่างพร้อมภาพจริงซึ่งดูเหมือนจะใช้งานได้ดี: jsfiddle.net/q2rzssxr/1
craig_h

ไม่แน่ใจว่าทำไมฉันจึงใช้งานได้โดยใช้รหัสที่ฉันเขียนไว้ในคำตอบอื่น ตัวอย่างของคุณใช้งานได้แม้ไม่มีฟังก์ชั่นนี้ดูที่นี่: jsfiddle.net/9a6Lg2vd/1
Saurabh

ในกรณีของฉันรูปภาพกำลังถูกเติมข้อมูลแบบอะซิงโครนัสโดยใช้ร้านค้า Vuex อาจมีบางอย่างที่ต้องทำฉันพยายามจำลอง แต่ไม่ได้ผล: jsfiddle.net/9a6Lg2vd/2
Saurabh

กรณีของฉันเป็นแบบนี้มากกว่า: jsfiddle.net/9a6Lg2vd/4แต่ในสัตว์เลี้ยงในพื้นที่ของฉันได้รับข้อมูลจากการโทร ajax แต่รูปภาพไม่ได้รับการแสดงผล
Saurabh

สิ่งนี้ยังใช้งานได้: jsfiddle.net/9a6Lg2vd/5ไม่แน่ใจว่าเหตุใดจึงไม่ทำงานกับเส้นทางไฟล์
Saurabh

6

ฉันยังประสบปัญหานี้และดูเหมือนว่าคำตอบที่โหวตส่วนใหญ่จะใช้งานได้ แต่มีปัญหาเล็กน้อย webpack ส่งข้อผิดพลาดไปยังคอนโซลเบราว์เซอร์ (ข้อผิดพลาด: ไม่พบโมดูล './undefined' ที่ webpackContextResolve) ซึ่งไม่ค่อยดีนัก

ฉันจึงแก้ไขมันให้แตกต่างออกไปเล็กน้อย ปัญหาทั้งหมดเกี่ยวกับคำสั่งตัวแปรภายในต้องการคือคำสั่งที่ต้องการถูกดำเนินการในระหว่างการรวมกลุ่มและตัวแปรภายในคำสั่งนั้นจะปรากฏเฉพาะในระหว่างการเรียกใช้แอปในเบราว์เซอร์ ดังนั้น webpack จึงมองเห็นภาพที่ต้องการโดยไม่ได้กำหนดไว้ทางใดทางหนึ่งเนื่องจากในระหว่างการรวบรวมตัวแปรนั้นไม่มีอยู่

สิ่งที่ฉันทำคือวางภาพแบบสุ่มลงในคำสั่งที่ต้องการและซ่อนภาพนั้นใน 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;
  }
}


3

คุณสามารถใช้ try catch block เพื่อช่วยในการไม่พบรูปภาพ

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 เป็นการพึ่งพาโมดูลผ่านตัวโหลด แต่สำหรับเส้นทางแบบไดนามิกคุณจำเป็นต้องใช้เพื่อแก้ไขเส้นทาง จากนั้นคุณสามารถสลับระหว่างรูปภาพโดยใช้ตัวแปรบูลีนและนิพจน์ด้านท้าย

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

และแน่นอนว่าจะสลับค่าของบูลีนผ่านตัวจัดการเหตุการณ์


ขอบคุณผลงานนี้:src="require(../assets/category_avatar/baby_kids.jpeg)"
Mohamed Raza

2

Vue.js ใช้vue-loaderตัวโหลดสำหรับ WebPack ซึ่งตั้งค่าให้เขียนใหม่ / แปลงเส้นทางในเวลาคอมไพล์เพื่อให้คุณไม่ต้องกังวลกับเส้นทางคงที่ซึ่งจะแตกต่างกันระหว่างการปรับใช้ (โลคัล, dev, หนึ่งแพลตฟอร์มโฮสติ้งหรืออื่น ๆ ) โดยช่วยให้คุณสามารถใช้เส้นทางระบบแฟ้มท้องถิ่นญาติ นอกจากนี้ยังเพิ่มประโยชน์อื่น ๆ เช่นการแคชเนื้อหาและการกำหนดเวอร์ชัน (คุณอาจเห็นสิ่งนี้ได้โดยตรวจสอบsrcURL จริงที่สร้างขึ้น)

ดังนั้นการมี src ที่ปกติจะจัดการโดยvue-loader/ WebPack ตั้งค่าเป็นนิพจน์แบบไดนามิกซึ่งประเมินที่รันไทม์จะหลีกเลี่ยงกลไกนี้และ URL แบบไดนามิกที่สร้างขึ้นจะไม่ถูกต้องในบริบทของการปรับใช้จริง (เว้นแต่ว่าจะมีคุณสมบัติครบถ้วนนั่นเป็นข้อยกเว้น ).

หากเป็นเช่นนั้นคุณจะใช้การrequireเรียกฟังก์ชันในนิพจน์ไดนามิกvue-loader/ WebPack จะเห็นและใช้เวทมนตร์ตามปกติ

ตัวอย่างเช่นสิ่งนี้ใช้ไม่ได้:

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

แม้ว่าจะใช้งานได้:

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

ฉันเพิ่งค้นพบเกี่ยวกับเรื่องนี้ด้วยตัวเอง ฉันใช้เวลาหนึ่งชั่วโมง แต่ ... คุณมีชีวิตอยู่คุณเรียนรู้ใช่ไหม? 😊


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>

0

ฉันพบปัญหาเดียวกัน สิ่งนี้ใช้ได้ผลสำหรับฉันโดยเปลี่ยน "../assets/" เป็น "./assets/"

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

0

พยายามหาคำตอบทั้งหมดที่นี่ แต่สิ่งที่ได้ผลสำหรับฉันใน Vue2 เป็นเช่นนี้

<div class="col-lg-2" v-for="pic in pics">
   <img :src="require(`../assets/${pic.imagePath}.png`)" :alt="pic.picName">
</div>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.