Skip to content

函数式组件

定义

在 Vue 中,常规组件通常是用选项对象来定义的,例如:

ts
export default {
  props: { msg: String },
  setup(props) {
    return () => h('div', props.msg)
  }
}
export default {
  props: { msg: String },
  setup(props) {
    return () => h('div', props.msg)
  }
}

函数式组件则不是一个对象,而是一个普通函数

ts
const MyComp = (props) => {
  return h('div', props.msg)
}

函数式组件是一种定义自身没有任何状态的组件的方式。它们很像纯函数:接收 props,返回 vnodes。

函数式组件在渲染过程中不会创建组件实例 (也就是说,没有 this),也不会触发常规的组件生命周期钩子。

ts
function MyComponent(props, { slots, emit, attrs }) {
  // ...
}

配置

大多数常规组件的配置选项在函数式组件中都不可用,除了 propsemits。我们可以给函数式组件添加对应的属性来声明它们:

ts
MyComponent.props = ['value']
MyComponent.emits = ['click']

如果这个 props 选项没有被定义,那么被传入函数的 props 对象就会像 attrs 一样会包含所有 attribute。除非指定了 props 选项,否则每个 prop 的名字将不会基于驼峰命名法被一般化处理。

对于有明确 props 的函数式组件,attribute 透传的原理与普通组件基本相同。然而,对于没有明确指定 props 的函数式组件,只有 classstyleonXxx 事件监听器将默认从 attrs 中继承。在这两种情况下,可以将 inheritAttrs 设置为 false 来禁用属性继承:

ts
MyComponent.inheritAttrs = false

函数式组件可以像普通组件一样被注册和使用。如果你将一个函数作为第一个参数传入 h,它将会被当作一个函数式组件来对待。

标注类型

具名函数式组件

ts
import type { SetupContext } from 'vue'
type FComponentProps = {
  message: string
}

type Events = {
  sendMessage(message: string): void
}

function FComponent(
  props: FComponentProps,
  context: SetupContext<Events>
) {
  return (
    <button onClick={() => context.emit('sendMessage', props.message)}>
        {props.message} {' '}
    </button>
  )
}

FComponent.props = {
  message: {
    type: String,
    required: true
  }
}

FComponent.emits = {
  sendMessage: (value: unknown) => typeof value === 'string'
}

匿名函数式组件

ts
import type { FunctionalComponent } from 'vue'

type FComponentProps = {
  message: string
}

type Events = {
  sendMessage(message: string): void
}

const FComponent: FunctionalComponent<FComponentProps, Events> = (
  props,
  context
) => {
  return (
    <button onClick={() => context.emit('sendMessage', props.message)}>
        {props.message} {' '}
    </button>
  )
}

FComponent.props = {
  message: {
    type: String,
    required: true
  }
}

FComponent.emits = {
  sendMessage: (value) => typeof value === 'string'
}