Vuejs - v-bind.sync для ресурсных компонентов (иерархический список)

У меня есть компонент иерархического списка, где у дочерних элементов есть флажки. Действия флажка (установить / снять отметку) должны синхронизировать родительский компонент с измененным состоянием флажка. Я не могу понять, как добиться этого с помощью рекурсивного v-bind.sync. Мой код выглядит следующим образом:

Menu.vue

Этот компонент содержит иерархический список. (Включен только соответствующий код)

  1. HierarchicalCheckboxList - это компонент, отображающий иерархический список
  2. Свойство value содержит значение проверки / снятия отметки (истина / ложь)
  3. Свойство children содержит элементы дочернего списка.

Как определить атрибут .sync в HierarchicalCheckboxList и с каким параметром?

<template>
<div>
    <HierarchicalCheckboxList
      v-for="link in links"
      @checked="primaryCheckChanged"
      :key="link.id"
      v-bind="link">
    </HierarchicalCheckboxList>
</div>
</template>
<script>
    import HierarchicalCheckboxList from 'components/HierarchicalCheckboxList'

    data () {
       return {
          links: [{
             id: 1,
             title: 'Home',
             caption: 'Feeds, Dashboard & more',
             icon: 'account_box',
             level: 0,
             children: [{
               id: 2,
               title: 'Feeds',
               icon: 'feeds',value: true,
               level: 1,
               children: [{
                  id: '3',
                  title: 'Dashboard',
                  icon: 'settings',
                  value: true,
                  level: 1
               }]
             }]
          }]
       }
    },
    methods: {
      primaryCheckChanged (d) {
        // A child's checked state is propogated till here
        console.log(d)
      }
    }
</script>

HierarchicalCheckboxList.vue

Этот компонент вызывает себя рекурсивно:

<template>
  <div>
    <div v-if="children != undefined && children.length == 0">
      <!--/admin/user/user-->
      <q-item clickable v-ripple :inset-level="level" :to="goto">
        <q-item-section>
          {{title}}
        </q-item-section>
      </q-item>
    </div>
    <div v-else>
      <div v-if="children != undefined && children.length > 0">
        <!-- {{children}} -->
        <q-expansion-item
            expand-separator
            :icon="icon"
            :label="title"
            :caption="caption"
            :header-inset-level="level"
            default-closed>
            <template v-slot:header>
              <q-item-section>
                {{ title }}
              </q-item-section>
              <q-item-section side>
                <div class="row items-center">
                  <q-btn icon="add" dense flat color="secondary"></q-btn>
                </div>
              </q-item-section>
            </template>
          <HierarchicalCheckboxList
            v-for="child in children"
            :key="child.id"
            @checked="primaryCheckChanged"
            v-bind="child">
          </HierarchicalCheckboxList>
        </q-expansion-item>
      </div>
      <!-- to="/admin/user/user" -->
      <div v-else>
        <q-item clickable v-ripple :inset-level="level">
          <q-item-section>
            <q-checkbox :label="title" v-model="selection" />
          </q-item-section>
        </q-item>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'HierarchicalCheckboxList',
  props: {
    id: { type: String, required: true },
    title: { type: String, required: false },
    caption: { type: String, default: '' },
    icon: { type: String, default: '' },
    value: { type: Boolean, default: false },
    level: { type: Number, default: 0 },
    children: { type: Array }
  },
  data () {
    return {
      localValue: this.$props.value
    }
  },
  computed: {
    selection: {
      get: function () {
        return this.localValue
      },
      set: function (newvalue) {
        this.localValue = newvalue
        this.$emit('checked', this.localValue) 
        // or this.$emit('checked', {id: this.$props.id, value: this.localValue })
      }
    }
  },
  methods: {
    primaryCheckChanged (d) {
      this.$emit('checked', d)
    }
  }
}
</script>

Что работает пока

В качестве обходного пути я могу получить состояние флажка, выдаваемое с помощью $ emit ('checked'), которое я использую для отправки его следующему процессу. Но состояние родителя не обновляется, пока я не обновлю его обратно из базы данных.

Как мне рекурсивно обновить состояние родительского компонента с помощью v-bind.sync?

Ценю любую помощь !!

UI

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


person A Mod    schedule 30.11.2020    source источник


Ответы (1)


Я понял, как это сделать, после того, как разбил код из всего кода 2000 строк на отдельный код «проб и ошибок» из 20 строк, и тогда все стало просто и понятно.

Menu.vue

Несколько изменений в родительском компоненте в объявлении HierarchicalCheckboxList: обратите внимание на свойство sync

<HierarchicalCheckboxList
   v-for="child in children"
   :key="child.id"
   :u.sync="link.value"
   v-bind="child">
</HierarchicalCheckboxList>

HierarchicalCheckboxList.vue

Измените ту же строку кода в дочернем компоненте (как его рекурсивный)

   <HierarchicalCheckboxList
     v-for="child in children"
     :key="child.id"
     :u.sync="child.value"
     v-bind="child">
   </HierarchicalCheckboxList>

И в свойстве вычисляемого набора испустите, как показано ниже:

   this.$emit('update:u', this.localValue)

Вот и все - родительские n дочерних компонентов теперь остаются в snyc.

person A Mod    schedule 01.12.2020