setup()
此页面记录了setup组件选项的使用。如果您将 Composition API 与单文件组件一起使用,建议使用<script setup>更简洁。
在以下情况下,该setup()钩子用作组件中组合 API 使用的入口点:
- 在没有构建步骤的情况下使用 Composition API;
 - 在 Options API 组件中与基于 Composition-API 的代码集成。
 
基本用法
我们可以使用响应式 API,声明反应状态,并通过从setup()返回对象的属性也将在组件实例上可用(如果使用其他选项):
<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>
请注意,在模板中访问时,从返回的refs,setup会自动浅展开.value,因此您在访问它们时不需要使用。当在组件上访问时,它们也以相同的方式展开this。
setup()本身无权访问组件实例。在setup()内, this的值不存在。您可以从 Options API 访问 Composition-API 公开的值,但反之则不行。
访问 props
setup()函数中的第一个参数是props,它是响应式的,并且会在传入新的props时更新。
export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}
注意:如果您对props对象进行解构,则被解构的变量将失去反应性。因此建议始终以props.xxx形式访问。
如果您确实需要解构props,或者需要将props传递给外部函数同时保持反应性,您可以使用toRefs()和toRef()实用程序 API 执行此操作:
import { toRefs } 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')
  }
}
设置上下文 context
传递给setup()函数的第二个参数是一个设置上下文context对象。上下文对象暴露了其他可能在setup()内部有用的值:
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)
  }
}
上下文对象不是响应式的,可以安全地解构:
export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}
attrs、slots是在组件本身更新时,始终更新的有状态对象。这意味着您应该避免对它们进行解构,并始终将属性引用为attrs.x或slots.x。
另请注意,与props不同,attrs、slots属性不是响应式的。如果您打算根据对其的更改应用副作用,则应在生命周期onBeforeUpdate挂钩中执行此操作。
暴露公共属性
默认状态下,本组件实例的属性方法,不能被父组件访问。expose()函数,可用于显式暴露:
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()还可以返回一个渲染函数,该函数可以直接使用在同一范围内声明的反应状态:
import { h, ref } from 'vue'
export default {
  setup() {
    const count = ref(0)
    return () => h('div', count.value)
  }
}
返回一个渲染函数,可以防止我们返回其他任何东西。在内部这应该不是问题,但是如果我们想通过模板引用将此组件的方法公开给父组件,则可能会出现问题。
我们可以通过调用expose()来解决这个问题:
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)
  }
}
然后,该
