Vue Draggable дочерние компоненты, изменяющие родительские данные

Структура моих приложений выглядит примерно так

App
    Column Component
        Task Component
        Task Component
        Task Component
    Column Component
        Task Component
        Task Component
    Column Component
    Column Component

введите описание изображения здесь

В каждом столбце есть <draggable> компонент, окружающий задачи. На уровне приложения у меня есть объект данных с разными столбцами и каждый столбец со своими задачами.

data: function() {
    return {
        columns: {
            new: [
                {
                    ID: 1,
                    title: 'The thing',
                    description: 'Prepare a proposal for facade'
                },
                {
                    ID: 2,
                    title: 'The thing 2',
                    description: 'Prepare a proposal for facade'
                },
                {
                    ID: 3,
                    title: 'The thing 3',
                    description: 'Prepare a proposal for facade'
                }
            ],
            inProgress: [
                {
                    ID: 4,
                    title: 'The thing 4',
                    description: 'Prepare a proposal for facade Store Opening Process (DEMO)'
                },
                {
                    ID: 5,
                    title: 'The thing 5',
                    description: 'Prepare a proposal for facade Store Opening Process (DEMO)'
                }
            ],
            done: [],
            onHold: []
        }
    }
}

Я перебираю столбцы и привязываю объект к компоненту:

<kool-column
    v-for="column"
    v-bind="colum"
></kool-column>

Компонент Kool Column:

<script id="kool-column-template" type="text/x-template">
    <div>
        <div>
            {{ column.name }} ({{ column.cards.length }})
        </div>
        <div>
            <draggable v-model="cards" group="columnkool">
                <div v-for="card in cards" :key="card.ID">
                    <kool-card v-bind="card"></kool-card>
                </div>
            </draggable>
        </div>
    </div>
</script>

<script>
    $(document).ready(function() {
        Vue.component('koolColumn', {
            template: '#kool-column-template',
            props: {
                ID: {
                    type: Number,
                    required: true
                },
                name: {
                    type: String,
                    required: true
                },
                cards: {
                    type: Array,
                    default: function() { return []; }
                }
            }
        });
    });
</script>

Итак, моя проблема, когда я перетаскиваю карты, я получаю сообщение об ошибке / предупреждении Vue:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "cards"

Имеет смысл, я читал и исследовал, и в Vue вы хотите использовать реквизиты для передачи данных в компоненты, но затем, чтобы изменить эти данные, вы отправляете событие родителю и позволяете родителю изменять его.

Хорошо, но библиотека, которую я использую, Vue Draggable изменяет список, который я ей передаю. Так что я должен делать? Решения, о которых я думал:

  1. При монтировании компонента столбца скопируйте карты свойств в данные компонента, используйте их для списка и модификаций, и каждый раз, когда он изменяется, отправляйте родительскому элементу новый список. Я не думаю, что это имеет большой смысл, у меня будет два источника информации (карточки в объекте приложения и карточки в объекте компонента моего столбца), и я рискую, что они не выровнены, в конце концов, я обновляю список раздельно.
  2. При отбрасывании элемента используйте библиотеку, чтобы фактически не допустить сброса (вы можете использовать события библиотеки и вернуть false, чтобы они фактически не меняли списки). Поймайте событие, отправьте родителю информацию о том, какой элемент был перетащен и пытался ли пользователь отбросить его, и соответствующим образом изменить данные. По сути, я бы использовал библиотеку перетаскивания, чтобы знать, где пользователь пытался что-то бросить, и фактически изменял данные вручную. Это также кажется странным, код действительно сложно уследить, и при падении элемента наблюдается мерцание (потому что он возвращается в исходное положение, а затем в то место, где вы хотели его иметь).
  3. Еще одно плохое решение - передать компоненту столбца не v-bind и каждое свойство по отдельности, а весь объект. Поэтому вместо v-bind="colum" я делаю :column="column", что фактически заставляет исчезнуть предупреждение Vue и сохраняет двойную привязку данных. Дело в том, что я использую анти-шаблон без предупреждения, но все же ... (кстати, этот подход исходит из этого примера: Управление задачами с помощью Vue)

Должен ли я продолжить подход №2? Уродливый, но, по крайней мере, не антипаттерн и не дублирующий информацию. Или есть другой способ сохранить двойную привязку данных, когда я не контролирую обновляемый список? Или, может быть, просто другая архитектура / структура для приложения ?.


person Joseph Pernerstorfer    schedule 25.11.2020    source источник
comment
Привет, Джозеф, у меня точно такая же проблема, как у вас: я хочу включить vue-dragable в компонент дочерней таблицы, где я передаю строки в качестве опоры. У меня такая же проблема с изменчивостью реквизита. Вы нашли ответ на свой вопрос? Что ты наконец сделал? Похоже, что в Интернете не так много подсказок о том, как хорошо работать с vuue-draggable внутри дочернего компонента.   -  person SebT    schedule 19.03.2021
comment
Привет @SebT, я делаю решение 3, которое я написал в посте.   -  person Joseph Pernerstorfer    schedule 20.03.2021


Ответы (1)


Vue draggable имеет 2 способа обработки предоставленных данных:

  1. при использовании v-model="array" это неизменяемо - при изменении порядка элементов создается новая копия.
  2. используя :list="array", он использует ту же ссылку и использует splice для обновления массива.

В вашем случае используйте :list="array", и все будет в порядке.

person Pirate    schedule 28.05.2021