跳转到内容

组合式API:setup()

基本用法

setup() 钩子在以下情况下作为组件中组合式API使用的入口点:

  1. 在不进行构建步骤的情况下使用组合式API;
  2. 将基于组合式API的代码集成到选项API组件中。

注意

如果您使用组合式API与单文件组件,强烈推荐使用 <script setup> 以获得更简洁、更直观的语法。

我们可以使用 响应性API 声明响应式状态,并通过从 setup() 返回一个对象将其暴露给模板。返回对象上的属性也将作为组件实例上的属性提供(如果使用了其他选项)

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

export default {
  setup() {
    const count = ref(0)

    // expose to template and other options API hooks
    return {
      count
    }
  },

  mounted() {
    console.log(this.count) // 0
  }
}
</script>

<template>
  <button @click="count++">{{ count }}</button>
</template>

setup 返回的 refs 在模板中访问时将自动浅解包,因此您在访问它们时不需要使用 .value。当在 this 上访问时,它们也会以相同的方式解包。

setup() 本身无法访问组件实例 - 在 setup() 内部,this 的值将是 undefined。您可以从选项API访问组合式API公开的值,但不能反向操作。

setup() 应该同步返回一个对象。唯一可以使用 async setup() 的情况是当组件是 Suspense 组件的子组件时。

访问属性

setup 函数中的第一个参数是 props 参数。正如您在标准组件中预期的那样,在 setup 函数内部的 props 是响应式的,并且当传入新的属性时将会更新。

js
export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

请注意,如果您解构了 props 对象,解构的变量将失去响应性。因此,建议始终以 props.xxx 的形式访问属性。

如果您确实需要解构属性,或者需要在保持响应性的同时将属性传递给外部函数,可以使用 toRefs()toRef() 工具 API 来实现。

js
import { toRefs, toRef } from 'vue'

export default {
  setup(props) {
    // turn `props` into an object of refs, then destructure
    const { title } = toRefs(props)
    // `title` is a ref that tracks `props.title`
    console.log(title.value)

    // OR, turn a single property on `props` into a ref
    const title = toRef(props, 'title')
  }
}

设置上下文

传递给 setup 函数的第二个参数是 设置上下文 对象。该上下文对象公开了在 setup 内可能有用的其他值。

js
export default {
  setup(props, context) {
    // Attributes (Non-reactive object, equivalent to $attrs)
    console.log(context.attrs)

    // Slots (Non-reactive object, equivalent to $slots)
    console.log(context.slots)

    // Emit events (Function, equivalent to $emit)
    console.log(context.emit)

    // Expose public properties (Function)
    console.log(context.expose)
  }
}

上下文对象不是响应式的,可以安全地解构。

js
export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

attrsslots 是状态对象,当组件本身更新时总是会被更新。这意味着您应该避免解构它们,并且始终以 attrs.xslots.x 的形式引用属性。此外,与 props 不同,attrsslots 的属性 不是 响应式的。如果您打算根据 attrsslots 的更改应用副作用,您应该在 onBeforeUpdate 生命周期钩子内部这样做。

公开公共属性

expose 是一个函数,可以用来显式限制当组件实例通过 模板引用 由父组件访问时暴露的属性。

js
export default {
  setup(props, { expose }) {
    // make the instance "closed" -
    // i.e. do not expose anything to the parent
    expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // selectively expose local state
    expose({ count: publicCount })
  }
}

与渲染函数一起使用

setup 还可以返回一个 渲染函数,该函数可以直接使用同一作用域中声明的响应式状态。

js
import { h, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    return () => h('div', count.value)
  }
}

返回渲染函数会阻止我们返回其他任何内容。从内部来看,这不应该是个问题,但如果我们想要通过模板引用将此组件的方法暴露给父组件,可能会出现问题。

我们可以通过调用 expose() 来解决这个问题。

js
import { h, ref } from 'vue'

export default {
  setup(props, { expose }) {
    const count = ref(0)
    const increment = () => ++count.value

    expose({
      increment
    })

    return () => h('div', count.value)
  }
}

然后,increment 方法将通过模板引用在父组件中可用。

组合式 API:setup() 已加载