vue3 defineComponent和setup-script的区别

6,619 阅读1分钟

defineComponent和setup-script都能用来定义组件,除了写法的复杂程度的区别比较大之外,主要就是props和emit写法的区别:

defineComponent的porps和emits写法与vue2时一样

  emits: {},
  props: {},

<script setup>需要用defineProps 和 defineEmits

<script setup>
    const props = defineProps({
      foo: String
    })

    const emit = defineEmits(['change', 'delete'])
</script>

如果是使用typeScript开发,porps还需要用到withDefaults

  interface Props {
    menu: string;
    isRunning?: boolean;
  }
  const props = withDefaults(defineProps<Props>(), { menu: '' });

defineComponent

从实现上看,defineComponent 只返回传递给它的对象。但是,就类型而言,返回的值有一个合成类型的构造函数,用于手动渲染函数、TSX 和 IDE 工具支持。

#参数

具有组件选项的对象

import { defineComponent } from 'vue'

export default defineComponent({
  name:'Component',
  components: {},
  emits: {},
  props: {
    goback: Boolean,
    showTitle: {
      type: Boolean,
      default: true,
    },
    header: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return { count: 1 }
  },
  methods: {
    increment() {
      this.count++
    }
  }
})

和vue2的option api的写法差不多

写setup 函数的时候

import { defineComponent } from 'vue'

export default defineComponent({
  name:'Component',
  components: {},
  emits: {},
  props: {
    goback: Boolean,
    showTitle: {
      type: Boolean,
      default: true,
    },
    header: {
      type: Object,
      default: () => ({}),
    },
  },
  setup(props,context) {
    const count = 1
    increment() {
      this.count++
    }
    return {count,increment}
  }
})

<script setup>

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 <script> 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 TypeScript 声明 props 和抛出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用,也不需要和defineComponent一样必须return出去

defineProps 和 defineEmits

在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 <script setup> 中是直接可用的,在使用ts时,搭配withDefaults使用更佳

<script setup lang="ts">
  import { useRouter } from 'vue-router';

  const emit = defineEmits(['change', 'delete'])

  interface Props {
    menu: string;
    isRunning?: boolean;
  }
  const props = withDefaults(defineProps<Props>(), { menu: '' });
  const route = useRouter();
  const onMenuClick = () => {
    route.push('/');
  };
</script>

defineExpose

使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

为了在 <script setup> 组件中明确要暴露出去的属性,使用 defineExpose 编译器宏:

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

useSlots 和 useAttrs

在 <script setup> 使用 slots 和 attrs 的情况应该是很罕见的,因为可以在模板中通过 $slots 和 $attrs 来访问它们。在你的确需要使用它们的罕见场景中,可以分别用 useSlots 和 useAttrs 两个辅助函数:

<script setup>
import { useSlots, useAttrs } from 'vue'

const slots = useSlots()
const attrs = useAttrs()
</script>

动态组件

由于组件被引用为变量而不是作为字符串键来注册的,在 <script setup> 中要使用动态组件的时候,就应该使用动态的 :is 来绑定:

<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>

<template>
  <component :is="Foo" />
  <component :is="someCondition ? Foo : Bar" />
</template>