最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I update image automatic on vue component when I upload the image? - Stack Overflow

programmeradmin2浏览0评论

My vue component like this :

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

The result of :src : \my-app\storage\app\public\banner\thumb\chelsea.png

When I upload image, it will call onFileChange method. And the process upload will continue in the backend. It success upload in the folder. And the response will return same filename. So the result of response.data.fileName is chelsea.png

My problem here is : it's not update the image automatic when I upload it. When I refresh the page, the image updated

Why the image is not automatic update/changed when I upload the image?

My vue component like this :

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

The result of :src : \my-app\storage\app\public\banner\thumb\chelsea.png

When I upload image, it will call onFileChange method. And the process upload will continue in the backend. It success upload in the folder. And the response will return same filename. So the result of response.data.fileName is chelsea.png

My problem here is : it's not update the image automatic when I upload it. When I refresh the page, the image updated

Why the image is not automatic update/changed when I upload the image?

Share Improve this question asked Mar 7, 2018 at 7:48 moses tohmoses toh 13.2k80 gold badges264 silver badges459 bronze badges
Add a comment  | 

8 Answers 8

Reset to default 7

I fixed it by doing the following, notice I added a variable named rand at the end of the photo url for cache busting. When you get a correct response from your server, simply change that variable to something unique (in this case a timestamp) and voila! your image will refresh.

<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()
                    }
                })
            },
        ...
    }

    }

Your images are cached by the browser.

Try to add any tag to the image like: chelsea.png?t=<random>

The answer, as provided above, are computed properties as these designed to be reactive, but when it comes to async it best to use promises / observables. However, if you decide not use and are still experiencing problems, then you can use a loading property, like the loading property in the example below to manipulate the DOM i.e. remove the DOM with v-if when you initiate async (axios). Get and set the the image and then restore the DOM element with this.loading = true;. This forces a render of the DOM, which forces a computed property.


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


Just use computed property, snippet below used getImageUrl to get the updated path. I added button to trigger the mimic change on the data provided.

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/[email protected]/dist/vue.js"></script>
<div id="app">
 <span>{{ getImageUrl }}</span>
 <br/>
 <button @click="mimicOnChange">
 On change trigger
 </button>
</div>

On you above code, just use the computed directly to your src attribute:

<img class="media-object" :src="getImageUrl" alt="" width="64" height="64"> 

Try binding full photo's path:

<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!!')
            })
        },
        ...
    }
}

I've had the same problem where inserting the same image won't trigger any action after the input. I fixed it by clearing the input.

clearInput(e) {
  e.target.value = '';
},

I had some weird behaviour with vue, where after upload the img, the base64 data, was on the src img, but the browser somehow did not render it correctly, only doing any action in the form like clicking any button etc.. would magically appear.

So that was solved using a 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)
    }

Looking at your question. I could not see whether you would like the process to be sync or async so I add my solution. I prefer to use Async/await in such cases and This should fix the problem of image render:

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)

  1. 暂无评论