Наблюдение за предложением ценности в Vue3 Composition API с помощью Typescript

Насколько я могу судить, то, что я делаю, должно работать правильно, основываясь на нескольких примерах, которые я нашел в Интернете, и на общем шаблоне, который, как мне кажется, я правильно понял из исходного кода ящика Wave UI.

В основном у меня есть компонент боковой панели, и я хочу, чтобы его можно было скрыть в соответствии с предоставленным ему значением (идея заключается в том, что его можно изменить в соответствии с потребностями родительского компонента, размером экрана, кнопкой переключения и т. Д.). Таким образом, компонент боковой панели имеет функцию наблюдения, которая должна реагировать на изменения в props.value.

Sidebar.vue

<template>
  <aside v-if="mountSidebar" class="min-h-screen">
    <slot></slot>
  </aside>
</template>

<script lang="ts">
import { defineComponent, ref, watch } from "vue";

export default defineComponent({
  name: "Sidebar",
  props: {
    value: {
      type: Boolean,
      default: true,
    },
  },
  setup(props) {
    const mountSidebar = ref(props.value);

    watch(
      () => props.value,
      (value) => {
        mountSidebar.value = value;
      }
    );

    return {
      close,
      mountSidebar,
    };
  },
});
</script>

И затем App.vue, где в настоящее время отображается боковая панель.

<template>
  <div>
    <navbar>
          <dm-button rounded type="primary" @click="showSidebar = !showSidebar">Toggle Sidebar</dm-button>
      Navbar Content
    </navbar>
    <div class="flex flex-row min-h-screen bg-gray-100 text-gray-800">
      <sidebar v-model="showSidebar">
        Sidebar Content
      </sidebar>
      <div class="flex justify-center w-full">
        <router-view />
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import Navbar from "@/components/Navbar.vue";
import Sidebar from "@/components/Sidebar.vue";
import DmButton from "@/components/Button.vue";

export default defineComponent({
  components: {
    Navbar,
    Sidebar,
    DmButton,
  },
  setup() {
    const showSidebar = ref(true);

    return {
      showSidebar,
    };
  },
});
</script>

В моем App.vue есть showSidebar логическая ссылка, которая предоставляется как v-model в компоненте боковой панели. Существует также dm-button (расширенный компонент кнопки, который я написал), который переключает значение showSidebar при нажатии (я знаю, что это работает, я вижу изменение значения showSidebar в компоненте App.vue в Vue Devtools). Однако это изменение не отражено в компоненте боковой панели. Я не уверен, что мне здесь не хватает.

К вашему сведению, этот код упрощен, чтобы удалить некоторые ненужные вещи (например, содержимое боковой панели и навигационных панелей).


person Christopher Leggett    schedule 08.05.2021    source источник


Ответы (2)


Чтобы использовать v-model с компонентом, вы должны назвать опору modelValue и испустить событие с именем update:modelValue, чтобы изменить его:

<template>
  <aside v-if="modelValue" class="min-h-screen">
    <slot></slot>
  </aside>
</template>

<script lang="ts">
import { defineComponent, ref, watch } from "vue";

export default defineComponent({
  name: "Sidebar",
  props: {
    modelValue: {
      type: Boolean,
      default: true,
    },
  },
emits:['update:modelValue'],
  setup(props,{emit}) {
  

      function close(){
         emit('update:modelValue',false)
      }

    return {
      close,
      mountSidebar,
    };
  },
});
</script>
person Boussadjra Brahim    schedule 08.05.2021
comment
Думаю, я просто не понимал, что часть испускания требовалась для дочернего элемента, чтобы прослушивать изменения v-модели, я думал, что это было просто для того, чтобы родитель мог прослушивать испускания и соответствующим образом корректировать свое состояние, если дочерний компонент также были способы мутировать собственное состояние, о которых родитель должен был знать. Важно ли название modelValue или это было просто для ясности? - person Christopher Leggett; 09.05.2021

Создавая новую ссылку из props.value, вы потеряли реактивность. props - это reactive, поэтому вы можете использовать _ 4_ или _ 5_.

const mountSidebar = toRef(props, 'value');
// or
const {value:mountSidebar} = toRefs(props);
person Sebastian Speitel    schedule 08.05.2021
comment
mountSidebar не должен быть реактивным, он просто получает свое начальное значение от реквизита. В конце концов, будет некоторая логика, так что при обновлении v-модели запускается анимация перехода, которая вручную изменяет mountSidebar и, возможно, другое значение, которое я еще не закодировал. Решение @BoussadjraBrahim решило мою проблему. - person Christopher Leggett; 09.05.2021