Skip to content

编译器宏

defineProps

父组件向子组件传递 属性 时,子组件需使用 defineProps 来接收,有三种使用方式:

typescript
const { msg } = defineProps<{ msg?: string }>();

// JavaScript原生语法设置默认值
const { msg = 'hello' } = defineProps<{ msg?: string }>()
typescript
const { msg } = defineProps({
  msg: {
    type: String,
    // 类型可以为多种的情况
    // type: [String, null],
    default: "Hello world",
    required: true
  }
});
typescript
interface IProps {
  msg?: string;
  label?: string[];
}

// 基于 interface 类型声明时,就失去了为 props 声明默认值的能力,可以通过 withDefaults 编译器宏解决
const { msg, label } = withDefaults(defineProps<IProps>(), {
  msg: "Hello world",
  label: () => ["one", "two"]
});
props的命名规范

如果一个 prop 的名字很长,应使用 camelCase 形式:

typescript
defineProps({
  greetingMessage: String
})

但在组件中传递属性时,为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式:

vue
<MyComponent greeting-message="hello" />

defineEmits

事件校验

要为 defineEmits 添加事件校验,需要返回一个布尔值来表明事件是否合法。

vue
<template>
	<HelloWorld @submit="handleSubmit" />
</template>

<script setup lang="ts">
  import HelloWorld from "./components/HelloWorld.vue"

  function handleSubmit(value: object) {
    console.log(value)
  }
</script>
vue
<template>
	<button @click="handleSubmit('admin', '123456')">submit</button>
</template>

<script setup lang="ts">
  const emit = defineEmits({
    click: null,
    submit: ({ username, password }) => {
      if (username && password) {
        return true
      } else {
        console.warn("Invalid submit event payload!")
        return false
      }
    }
  })

  function handleSubmit(username: string, password: string) {
    emit("submit", { username, password })
  }
</script>

defineOptions3.3+

defineOptions 宏可以用来直接在 <script setup> 中声明 组件选项,而不必使用单独的 script 块:

vue
<script>
  export default {
    name: "MyComponent"
  }
</script>

<script lang="ts" setup></script>
vue
<script>
	import { defineComponent, defineOptions, ref } from 'vue'

  export default defineComponent({
    name: "MyComponent",
    setup() {
      defineOptions({
        name: "MyComponent"
      })
    }
  })
</script>
vue
<script lang="ts" setup>
	defineOptions({
    name: "MyComponent",
    inheritAttrs: false,
    customOptions: {
      /* ... */
    }
  })
</script>

defineModel

参考文章:https://juejin.cn/post/7338262742816981044#heading-2

definedModel() 宏返回的是一个 ref,它可以正常使用 .value 被访问和修改,它最重要的作用是在 父组件和子组件之间实现双向绑定

  • 子组件的 .value 和父组件的 v-model 的值同步;
  • 当子组件的值变化了,会立马触发父组件绑定的值一起更新;

默认v-model

vue
<template>
  <h5>{{ count }}</h5>
  <HelloWorld v-model="count" />
</template>

<script setup lang="ts">
  import { ref } from "vue";
  import HelloWorld from "./components/HelloWorld.vue";

  const count = ref<Number>(2000);
</script>
vue
<template>
	<input type="text" v-model="model" />
</template>

<script setup lang="ts">
  const model = defineModel<Number>();
  console.log(modle.value);    // 2000
</script>

具名v-model

vue
<template>
  <h5>{{ count }}</h5>
  <HelloWorld v-model:count="count" />
</template>

<script setup lang="ts">
  import { ref } from "vue";
  import HelloWorld from "./components/HelloWorld.vue";

  const count = ref<Number>(2000);
</script>
vue
<template>
	<input type="text" v-model="model" />
</template>

<script setup lang="ts">
  const model = defineModel<Number>("count");
  console.log(model.value);  // 2000
</script>

绑定多个v-model

vue
<template>
  <h5>{{ count }}</h5>
  <HelloWorld v-model:count="count" v-model:name="name" />
  <h5>{{ name }}</h5>
  <HelloWorld v-model:count="count" v-model:name="name" />
</template>

<script setup lang="ts">
  import { ref } from "vue";
  import HelloWorld from "./components/HelloWorld.vue";

  const count = ref<Number>(2000);
  const name = ref<String>("tom");
</script>
vue
<template>
  <input type="text" v-model="model" />
  <input type="text" v-model="model2" />
</template>

<script setup lang="ts">
  const model = defineModel<Number>("count");
  console.log(model.value); // 2000

  const model2 = defineModel<String>("name");
  console.log(model2.value); // tom
</script>

props选项

vue
<template>
  <h5>{{ visible }}</h5>
  <HelloWorld v-model:visible="visible" />
</template>

<script setup lang="ts">
  import { ref } from "vue";
  import HelloWorld from "./components/HelloWorld.vue";

  const visible = ref<boolean>(true);
</script>
vue
<template>
  <input type="text" v-model="model" />
</template>

<script setup lang="ts">
  const model = defineModel("visible", {
    type: boolean,
    required: true,
    default: true,
    // 校验值,传入的值必须是true或false
    validator: (value: string) => [true, false].includes(value)
  });
</script>

Released under the MIT License.