Как я могу передать массив объектов в качестве реквизита компоненту, а затем передать элементы массива в качестве реквизита вложенным компонентам?

В нижней части этого поста в редактировании я указываю, чего я хочу достичь и что почти сработало

Ниже приведено мое приложение с компонентами <oo-upload> и <oo-uploads>, определенными над приложением. По сути, <oo-uploads> отображает таблицу компонентов <oo-upload> для создания плагина загрузки файлов для моего приложения. Переменная uploads представляет собой список всех загрузок, а upload определяет каждую отдельную загрузку.

<body>

    <script type="x/template" id="oo-upload-template">
        <td>@{{ upload.file.name }}</td>
        <td>@{{ upload.file.size }}</td>
        <td>
            <div class="ui indicating progress floated" v-progress="upload.progress">
                <div class="bar"><div class="progress"></div></div>
            </div>
        </td>
        <td>
            <button class="ui primary button" v-on:click="upload" v-if="status < 1">Upload</button>
            <button class="ui red button" v-on:click="destroy" v-if="status == 2">Delete</button>
        </td>
    </script>

    <script type="x/template" id="oo-uploads-template">
        <table class="ui very basic table">
            <thead>
                <tr>
                    <th class="two wide">Filename</th>
                    <th class="two wide">Filesize</th>
                    <th class="ten wide">Status</th>
                    <th class="two wide">Actions</th>
                </tr>
            </thead>

            <tbody>
                <tr v-show="uploads.length==0">
                    <td colspan="4" class="ui center aligned">No files added!</td>
                </tr>
                <tr v-for="upload in uploads">
                    <oo-upload :upload="upload"></oo-upload>
                </tr>
            </tbody>

            <tfoot class="full-width">
                <tr>
                    <th colspan="4">
                        <div class="ui right floated small green labeled icon button" v-on:click="uploadDialog">
                            <i class="plus icon"></i> Upload File
                            <input type="file" style="display:none;" v-el:uploader v-on:change="addFiles" multiple>
                        </div>
                    </th>
                </tr>
            </tfoot>
        </table>
    </script>

    <div id="app">
        <div class="ui container">
            <oo-uploads :uploads="uploads"></oo-uploads>
        </div>
    </div>
    <script type="text/javascript" src="js/app.js"></script>
</body>

Проблема в том, что объект objUpload не передается каждому экземпляру компонента <oo-upload>. Вместо этого отладчик Vue говорит, что компоненту передается функция, а не объект. У <oo-uploads> нет проблем с получением uploads в качестве реквизита.

var Vue = require('vue'),
    VueRouter = require('vue-router'),
    VueResource = require('vue-resource'),
    Vuex = require('vuex'),
    VueValidator = require('vue-validator');

/*
PLUGINS
 */

Vue.use(VueResource);

/*
CUSTOM DIRECTIVES
 */

Vue.directive('progress', {
    bind: function () {
        $(this.el).progress();
    },
    update: function (value) {
        $(this.el).progress('set percent', value);
    }
});

/*
OBJECTS
 */

function objUpload (file) {
    this.progress = 0;
    this.file = file;
    this.status = 0;
}

/*
COMPONENTS
 */

Vue.component('oo-upload', {
    props: ['upload'],
    template: '#oo-upload-template',
    methods: {
        upload: function () {
            this.upload.status = 1;
            this.$http.post('/upload', this.upload.file, { progress: function (pe) {
                this.progress = Math.floor(pe.loaded/pe.total * 100);
            }}).then(function (result) {
                this.upload.status = 2;
            }, function (result) {
                this.upload.status = -1;
            })
        },
        destroy: function () {

        }
    }
});

Vue.component('oo-uploads', {
    props: ['uploads'],
    template: '#oo-uploads-template',
    methods: {
        uploadDialog: function () {
            $(this.$els.uploader).click();
        },
        addFiles: function () {
            var uploader = this.$els.uploader;
            for (var i = 0; i < uploader.files.length; i++) {
                var file = uploader.files[i];
                this.uploads.push(new objUpload(file));
            }
        }
    }
})

/*
CONSTANTS
 */

Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name="_token"]').attr('content');

/*
INSTANCE
 */

var vm = new Vue({
    el: '#app',
    data: {
        uploads: [],
    },
});

РЕДАКТИРОВАТЬ: Если я передам массив uploads непосредственно одному экземпляру <oo-upload> в пределах <oo-uploads>, он отлично передаст весь массив, но по какой-то причине он не будет перебирать массив и передавать только объекты objUpload.

EDIT2: По сути, я хочу ограничить объем данных, которые я передаю, только тем, что необходимо для этого компонента. Я хочу, чтобы компонент загрузки действовал только на назначенную ему загрузку. Я понимаю, что моя практика может быть плохой или что моя реализация может быть невозможной, мне просто нужен указатель, как сделать что-то подобное.


person gopher    schedule 12.08.2016    source источник


Ответы (1)


Согласно документации Vue.js

Поэтому рекомендуется всегда иметь в шаблонах один простой элемент корневого уровня.

Попробуйте обернуть oo-upload-template tr и изменить

<tr v-for="upload in uploads">
  <oo-upload :upload="upload"></oo-upload>
</tr>

to

<tr is="oo-upload" v-for="upload in uploads" :upload="upload"></tr>

Пример исправленной скрипки

person pkawiak    schedule 12.08.2016
comment
Знаете ли вы, почему строки отображаются над таблицей, а не внутри нее как строки? - person gopher; 12.08.2016
comment
Ой, забыл про ужасный случай с таблицей... как сказано в docs < i>table может содержать только thead, tbody, tfoot и tr, и эти элементы должны быть прямыми дочерними элементами table, потому что пользовательские теги будут удалены и, следовательно, не будут правильно отображаться. Я обновил ответ, чтобы использовать is - person pkawiak; 12.08.2016
comment
Я внес все изменения, которые вы предложили, но они не начали работать, пока я не сломал upload и не передал его свойства по отдельности как <tr is="oo-upload" v-for="upload in uploads" :file="upload.file" :status="upload.status" :progress="upload.progress"></tr>. Я понятия не имею, почему, хотя... - person gopher; 12.08.2016