使用 Typescript 观察 Vue3 Composition API 中的 Value Prop

Watching Value Prop in Vue3 Composition API with 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 的值(我知道这有效,我可以看到 App.vue 组件中的 showSidebar 值发生变化Vue 开发工具)。但是,更改不会反映在侧边栏组件中。我不确定我在这里遗漏了什么。

仅供参考,此代码已简化,删除了一些不必要的内容(例如侧边栏和导航栏中的内容)。

要将 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>

通过从 props.value 创建一个新的引用,你失去了反应性。 propsreactive, so you can use toRef or toRefs.

const mountSidebar = toRef(props, 'value');
// or
const {value:mountSidebar} = toRefs(props);