Ключ / значение объекта VueJs не реагирует в цикле v-for - PullRequest
3 голосов
/ 12 июня 2019

У меня есть следующая проблема, которую я не знаю, как правильно ее решить.

У меня есть "список" всех купленных изображений на мой взгляд. Я отображаю их с помощью v-for loop. Каждое изображение также имеет элемент индикатора выполнения, поэтому, когда пользователь нажимает кнопку загрузки, запускается функция downloadContent и должна отображаться индикатор выполнения.

Так что мой HTML выглядит так.

<section class="stripe">
    <div class="stripe__item card" v-for="(i, index) in purchasedImages">
        <progress-bar :val="i.download_progress"
                      v-if="i.download_progress > 0 && i.download_progress < 100"></progress-bar>
        <div class="card__wrapper">
            <img :src="'/'+i.thumb_path" class="card__img">
        </div>
        <div class="btn-img card__btn card__btn--left" @click="downloadContent(i.id_thumb, 'IMAGE', index)">
        </div>
    </div>
</section>

А это мой код JS

import Vue from 'vue'
import orderService from '../api-services/order.service';
import downloadJs from 'downloadjs';
import ProgressBar from 'vue-simple-progress';

export default {
    name: "MyLocations",
    components: {
        ProgressBar: ProgressBar
    },
    data() {
        return {
            purchasedImages: {},
            purchasedImagesVisible: false,
        }
    },
    methods: {
        getUserPurchasedContent() {
            orderService.getPurchasedContent()
                .then((response) => {
                    if (response.status === 200) {

                        let data = response.data;
                        this.purchasedImages = data.images;

                        if (this.purchasedImages.length > 0) {
                            this.purchasedImagesVisible = true;
                            // Set download progress property
                            let self = this;
                            this.purchasedImages.forEach(function (value, key) {
                                self.purchasedImages[key].download_progress = 0;
                            });
                        }
                    }
                })
        },
        downloadContent(id, type, index) {
            let self = this;
            orderService.downloadContent(id, type)
                .then((response) => {
                    let download = downloadJs(response.data.link);
                    download.onprogress = function (e) {
                        if (e.lengthComputable) {
                            let percent =  e.loaded / e.total * 100;
                            let percentage = Math.round(percent);
                            if (type === 'IMAGE') {
                            // Is this proper way to set one field reactive?
                         self.purchasedImages[index].download_progress = percentage;
                                if (percentage === 100) {
                                    self.purchasedImages[index].download_progress = 0;
                                }
                            }
                        }
                    }
                })
        },
    },
    mounted: function () {
        this.getUserPurchasedContent();
    }
};

Так что проблема в том. Когда пользователь нажимает кнопку загрузки, загрузка начинает выполняться, и я получаю загруженный контент, но не вижу индикатор выполнения. Итак, мне интересно, это правильный способ установить элемент реагировать? Как должна выглядеть моя реализация? Как правильно установить self.purchasedImages[index].download_progress значение ключа объекта, чтобы индикатор выполнения был виден?

Если вам нужна дополнительная информация, пожалуйста, дайте мне знать, и я предоставлю. Спасибо!

1 Ответ

4 голосов
/ 12 июня 2019

Фрагмент:

this.purchasedImages = data.images;

Приводит нас к мысли, что data.images - это массив объектов, у которых нет свойства download_progress. Поэтому Vue не может обнаружить / отреагировать, когда он изменится.

Чтобы исправить это, вы можете использовать Vue.set:

Vue.set(self.purchasedImages[key], 'download_progress', 0);

Это очень хорошо объяснено в Vue.js документах .


Другой вариант: добавить свойство перед присвоением data

Просто для полноты можно добавить download_progress до , присваивая массив свойству data. Это позволило бы Vue заметить это и иметь возможность реагировать на это.

Пример:

let data = response.data;
this.purchasedImages = data.images.map(i => ({...i, download_progress: 0}));

if (this.purchasedImages.length > 0) {
    this.purchasedImagesVisible = true;
    // no need to set download_progress here as it was already set above
}

// if above could also be simplified to just:
this.purchasedImagesVisible = this.purchasedImages.length;




Кстати, поскольку это будет массив, а не объект, я предлагаю вам объявить его так:

data() {
    return {
        purchasedImages: [], // was: {},

Это не будет иметь никакого эффекта, поскольку вы полностью перезаписываете purchasedImages в (this.purchasedImages = data.images;), но это хорошая практика, поскольку она документирует тип этого свойства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...