当我上传图片时,如何在Vue组件上自动更新图片?

8
我的Vue组件如下:
<template>
    <section>
        ...
            <img class="media-object" :src="baseUrl+'/storage/banner/thumb/'+photo" alt="" width="64" height="64"> 
        ...
    </section>
</template>
<script>
    export default {
        props: ['banners'],
        data() {
            return {
                baseUrl: App.baseUrl,
                bannerId: this.banners.id,
                photo: this.banners.photo // result : chelsea.png
            }
        },
        methods: {
            onFileChange(e) {
                let files = e.target.files,
                    reader = new FileReader(),
                    formData = new FormData(),
                    self = this

                formData.append('file', files[0])
                formData.append('banner_id', this.bannerId)

                axios.post(window.App.baseUrl+'/admin/banner/upload-image',
                formData,
                {
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    }
                }
                ).then(function(response) {
                    if(response.data.status == 'success') {
                        self.photo = response.data.fileName // result : chelsea.png
                    }
                })
                .catch(function(error) {
                    console.log('FAILURE!!')
                })
            },
            ...
        }
    }
</script>
< p >:src的结果为:\ my-app \ storage \ app \ public \ banner \ thumb \ chelsea.png < /p> < p >当我上传图片时,它会调用onFileChange方法。上传过程将在后端继续进行。它成功地上传到文件夹中。响应将返回相同的文件名。因此,response.data.fileName的结果是chelsea.png。

我的问题是:上传图片后它不会自动更新图片。当我刷新页面时,图片才被更新。

为什么我上传图片后图片不会自动更新/更改?

8个回答

7
我通过以下方式解决了这个问题,注意我在照片URL的末尾添加了一个名为rand的变量进行缓存清除。当你从服务器中获得正确的响应后,只需将该变量更改为唯一的内容(在本例中是时间戳),图片就会刷新。
<template>
    <img class="media-object" :src="baseUrl+'/storage/banner/thumb/'+photo + '?rand=' + rand" alt="" width="64" height="64"> 
</template>
<script>
    export default {
        data() {
           return {
               rand: 1
           }
        },
        methods: {
            onFileChange(e) {
                ...
                axios.post(url,formData).then(function(response) {
                    if(response.data.status == 'success') {
                        self.rand = Date.now()
                    }
                })
            },
        ...
    }

    }

4
您的图片已被浏览器缓存。
尝试向图像添加任何标记,如:chelsea.png?t=<random>

有时候它会给我相同的图片,但是刷新后就变了,我该如何修复它而不重命名图片本身? - Freddy Sidauruk
通常情况下,我们的后端会给我们一个带有MIME类型的图像路径,例如/image/12334。不会返回image.png。 - Luciens

2

如上所述,答案是计算属性,因为它们被设计为具有反应性,但在涉及异步操作时,最好使用 promises / observables。然而,如果您决定不使用并且仍然遇到问题,则可以使用加载属性,例如下面示例中的 loading 属性来操作 DOM,即在启动异步(axios)时使用 v-if 删除 DOM。获取和设置图像,然后使用 this.loading = true; 恢复 DOM 元素。这强制渲染 DOM,从而强制进行计算属性。


<template>
    <section>
        <div v-if="!loading">
            <img class="media-object" :src="getPhoto" :alt="getAlt" width="64" height="64">
        </div>
        <div v-if="loading">
<!--            OR some spinner-->
            <div>Loading image</div>
        </div>
    </section>
</template>
<script>
    export default {
        props: ['banners'],
        data() {
            return {
                loading: false,
                baseUrl: App.baseUrl,
                bannerId: this.banners.id,
                photo: {} // result : chelsea.png
            }
        },
        computed: {
            getPhoto() {
                return App.baseUrl + '/storage/banner/thumb/' + this.photo.fileName;
            },
            getAlt() {
                return photo.alt;
            },
        },
        methods: {
            onFileChange(e) {
                let files = e.target.files,
                    reader = new FileReader(),
                    formData = new FormData(),
                    self = this

                // Set loading to true 
                this.loading = true;

                formData.append('file', files[0])
                formData.append('banner_id', this.bannerId)

                axios.post(window.App.baseUrl+'/admin/banner/upload-image',
                    formData,
                    {
                        headers: {
                            'Content-Type': 'multipart/form-data'
                        }
                    }
                ).then(function(response) {
                    if(response.data.status == 'success') {
                        self.photo = response.data.fileName // result : chelsea.png
                        this.loading = false;
                    }
                })
                    .catch(function(error) {
                        console.log('FAILURE!!')
                    })
            },
            ...
        }
    }
</script>



1
只需使用计算属性,下面的代码片段使用getImageUrl获取更新后的路径。我添加了一个按钮来触发提供的数据的模拟更改。

new Vue({
 el: "#app",
  data: {
   baseUrl: 'baseURl', //dummy
    bannerId: '', //dummy
    photo: 'initPhoto.png' // dummy
  },
  computed: {
   getImageUrl: function() {
     return this.baseUrl + '/storage/banner/thumb/' + this.photo;
    }
  },
  methods: {
   mimicOnChange: function() {
     this.photo = "chelsea.png"
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<div id="app">
 <span>{{ getImageUrl }}</span>
 <br/>
 <button @click="mimicOnChange">
 On change trigger
 </button>
</div>

在您的上述代码中,只需直接使用计算结果作为src属性即可:
<img class="media-object" :src="getImageUrl" alt="" width="64" height="64"> 

0

尝试绑定完整照片路径:

<template>
<section>
    ...
        <img v-if="photoLink" class="media-object" :src="photoLink" alt="" width="64" height="64"> 
        <p v-text="photoLink"></p>
    ...
</section>
</template>
<script>
export default {
    props: ['banners'],
    data() {
        return {
            baseUrl: App.baseUrl,
            bannerId: this.banners.id,
            photo: this.banners.photo, // result : chelsea.png
            photoLink: App.baseUrl + '/storage/banner/thumb/' + this.banners.photo 
        }
    },
    methods: {
        onFileChange(e) {
            let files = e.target.files,
                reader = new FileReader(),
                formData = new FormData(),
                self = this

            formData.append('file', files[0])
            formData.append('banner_id', this.bannerId)

            axios.post(window.App.baseUrl+'/admin/banner/upload-image',
            formData,
            {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }
            ).then(function(response) {
                if(response.data.status == 'success') {
                    // self.photo = response.data.fileName // result : chelsea.png
                    console.log('>>>INSIDE SUCCESS');
                    self.photoLink = self.baseUrl + '/storage/banner/thumb/' + response.data.fileName;
                }
            })
            .catch(function(error) {
                console.log('FAILURE!!')
            })
        },
        ...
    }
}


你能通过打印 console.log('>>>INSIDE SUCCESS'); 来确保 'success' 内的代码正在执行吗?并且 <p v-text="photoLink"></p> 是否会更新为新的 photoLink? - Sajib Khan
console.log('>>>INSIDE SUCCESS'); 的结果会显示在控制台上。但是图片没有更新。 - moses toh
<p v-text="photoLink"></p> 是否在更新? - Sajib Khan
这似乎是因为文件名与响应中的文件名相同。文件名:chelsea.png。如果文件名与响应不同,则可以正常工作。但是在这里,我希望文件名相同。 - moses toh
是的,我也这么认为。尝试使用 v-if 强制重新渲染。 - Sajib Khan
显示剩余2条评论

0

我在使用 Vue 时遇到了一些奇怪的问题,上传图片后,base64 数据会出现在图片的 src 属性中,但浏览器似乎不能正确地渲染它,只有在表单中执行任何操作(如点击任何按钮等)才会神奇地出现。

因此,我使用了 setTimeout 来解决这个问题。

uploadNewImg () {
      let self = this
      // Get the selected file
      var file = this.$refs.profileImg.files[0]
      // Create a new FileReader object
      var reader = new FileReader()
    
      reader.onload = function (e) {
            // Create a new FormData object
            var formData = new FormData()
            formData.append('file', file)
           
            setTimeout(function () {
                self.profilePic = e.target.result// this is used as src of img tag
              }, 1)
    }

0
看了你的问题,我没有看出你想要同步还是异步处理,所以我提供我的解决方案。在这种情况下,我更喜欢使用Async/await,这应该可以解决图像渲染的问题:
async onFileChange(e) {
  let formData = new FormData();
  formData.append('file', files[0]);
  formData.append('banner_id', this.bannerId);
  //.... Add headers and payload for post request
  const {data} = await axios.post(window.App.baseUrl+'/admin/banner/upload-image', payload);

  if(data.status === 'success') {
    self.photo = data.fileName // result : chelsea.png
  }
}

0
我遇到了同样的问题,即插入相同的图像后,输入不会触发任何操作。我通过清除输入来解决了这个问题。
clearInput(e) {
  e.target.value = '';
},

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接