Не удается изменить данные верхнего уровня объекта слота в Vue - PullRequest
1 голос
/ 20 апреля 2020

Если вы запустите эту демонстрацию и нажмете «изменить в дочернем», текст будет обновлен. Но если вы нажмете «изменить верхний уровень через слот», он не будет обновлен, и после щелчка по нему нажатие другой кнопки больше не будет работать.

Как я могу обновить свойство верхнего уровня слота ? Например, логическое значение или строка. Выполнение этого непосредственно в дочернем процессе работает, но я не могу сделать это через слот.

Если дочерние данные содержат объект, я могу изменить дочернее свойство этого объекта данных через слот (см. Оригинал версия этого вопроса до правки для демонстрации этого), но я не могу изменить свойство верхнего уровня.

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: "initial"
      }
    }
  },
  methods: {
    click() {
      this.object.string = "modify in child"
    }
  }
}
new Vue({
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
          </div>`,
  methods: {
    click(slot) {
      slot.string = "updated top level through slot"
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>

1 Ответ

0 голосов
/ 20 апреля 2020

Что касается того, почему вы видите такое поведение, когда вы не можете изменить объект root, но можете изменить свойства под ним, открытая переменная слота является мелким клоном, поэтому ссылка на верхний уровень не совпадает с ссылка на объект в дочернем компоненте. Я добавил console.log и обернул .string в объект, чтобы показать его. Нажмите child, а затем modify кнопки.

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

Прямая ссылка и изменение состояния дочерних компонентов является антипаттерном. Это должно стимулировать разработку компонентов, которые имеют детерминированное поведение c, и поддерживать разделение компонентов (чтобы они оставались автономными и многоразовыми). Также есть некоторые преимущества в производительности.

Этот парень хорошо это объясняет: { ссылка }
Vue и React основаны на схожих концепциях.

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: {x: "initial"}
      }
    }
  },
  methods: {
    click() {
      window.ChildObjectReference = this.object;
      this.object.string.x = "modify in child"
    }
  }
}
new Vue({
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
          </div>`,
  methods: {
    click(slot) {
      console.log( `slot: `,slot, `\nobject = `, window.ChildObjectReference,
         `\nslot !== ref as object: `, slot === window.ChildObjectReference,
         `\nslot.string === ref object.string: `, slot.string === window.ChildObjectReference.string)
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>

Отображение взаимодействия между слотом и родительским компонентом:

const Child = {
  template: `<div>
          {{ object }}
          <slot name="named" v-bind="object">
          </slot>
          <button @click="click">child</button>
        </div>`,
  data() {
    return {
      object: {
        string: "initial"
      }
    }
  },
  methods: {
    click() {
      this.object.string = "modify in child"
    }
  }
}
new Vue({
  data: {
    topLevelObject: { property: "top level initial" }
  },
  components: {
    Child,
  },
  template: `
          <div class="page1">
            <Child>
              <template v-slot:named="slot">
                <div>this is v-bind:'object' on slot 'named' put into variable slot: {{ slot }}</div>
                <button @click="click(slot)">modify top level through slot</button>
              </template>
            </Child>
            Top Level state: {{ topLevelObject }}
          </div>`,
  methods: {
    click(slot) {
      this.topLevelObject.property = "slot.string pushed to top level: " + slot.string
    }
  }
}).$mount('#app')
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...