组件之间通信
Reka UI 组件库中各个组件之间的通信机制。
Reka UI 组件主要通过以下几种方式进行通信:
Context Provider/Inject 模式
组件使用 Vue 的 provide/inject 模式在组件树中共享状态和方法。 CalendarRoot.vue:13-45 每个根组件都会创建一个 context 来提供共享的状态和回调函数给子组件使用。 SelectRoot.vue:59-60
type CalendarRootContext = {
locale: Ref<string>
modelValue: Ref<DateValue | DateValue[] | undefined>
placeholder: Ref<DateValue>
pagedNavigation: Ref<boolean>
preventDeselect: Ref<boolean>
grid: Ref< Grid<DateValue>[]>
weekDays: Ref<string[]>
weekStartsOn: Ref<0 | 1 | 2 | 3 | 4 | 5 | 6>
weekdayFormat: Ref<WeekDayFormat>
fixedWeeks: Ref<boolean>
multiple: Ref<boolean>
numberOfMonths: Ref<number>
disabled: Ref<boolean>
readonly: Ref<boolean>
initialFocus: Ref<boolean>
onDateChange: (date: DateValue) => void
onPlaceholderChange: (date: DateValue) => void
fullCalendarLabel: Ref<string>
parentElement: Ref<HTMLElement | undefined>
headingValue: Ref<string>
isInvalid: Ref<boolean>
isDateDisabled: Matcher
isDateSelected: Matcher
isDateUnavailable?: Matcher
isOutsideVisibleView: (date: DateValue) => boolean
prevPage: (prevPageFunc?: (date: DateValue) => DateValue) => void
nextPage: (nextPageFunc?: (date: DateValue) => DateValue) => void
isNextButtonDisabled: (nextPageFunc?: (date: DateValue) => DateValue) => boolean
isPrevButtonDisabled: (prevPageFunc?: (date: DateValue) => DateValue) => boolean
formatter: Formatter
dir: Ref<Direction>
}
export const [injectSelectRootContext, provideSelectRootContext]
= createContext<SelectRootContext<AcceptableValue>>('SelectRoot')
事件发射机制
组件通过 Vue 的 emit 系统向父组件发送事件通知状态变化。 RangeCalendarRoot.vue:107-114 例如,当日期选择发生变化时,会发射 update:modelValue 事件。
export type RangeCalendarRootEmits = {
/** Event handler called whenever the model value changes */
'update:modelValue': [date: DateRange]
/** Event handler called whenever the placeholder value changes */
'update:placeholder': [date: DateValue]
/** Event handler called whenever the start value changes */
'update:startValue': [date: DateValue | undefined]
}
回调函数传递
在 context 中定义的回调函数允许子组件直接调用父组件的方法来更新状态。 CalendarRoot.vue:29-30 比如 onDateChange 和 onPlaceholderChange 函数。
type CalendarRootContext = {
locale: Ref<string>
modelValue: Ref<DateValue | DateValue[] | undefined>
placeholder: Ref<DateValue>
pagedNavigation: Ref<boolean>
preventDeselect: Ref<boolean>
grid: Ref< Grid<DateValue>[]>
weekDays: Ref<string[]>
weekStartsOn: Ref<0 | 1 | 2 | 3 | 4 | 5 | 6>
weekdayFormat: Ref<WeekDayFormat>
fixedWeeks: Ref<boolean>
multiple: Ref<boolean>
numberOfMonths: Ref<number>
disabled: Ref<boolean>
readonly: Ref<boolean>
initialFocus: Ref<boolean>
onDateChange: (date: DateValue) => void // 回调函数
onPlaceholderChange: (date: DateValue) => void // 回调函数
fullCalendarLabel: Ref<string>
parentElement: Ref<HTMLElement | undefined>
headingValue: Ref<string>
isInvalid: Ref<boolean>
isDateDisabled: Matcher
isDateSelected: Matcher
isDateUnavailable?: Matcher
isOutsideVisibleView: (date: DateValue) => boolean
prevPage: (prevPageFunc?: (date: DateValue) => DateValue) => void
nextPage: (nextPageFunc?: (date: DateValue) => DateValue) => void
isNextButtonDisabled: (nextPageFunc?: (date: DateValue) => DateValue) => boolean
isPrevButtonDisabled: (prevPageFunc?: (date: DateValue) => DateValue) => boolean
formatter: Formatter
dir: Ref<Direction>
}
响应式状态共享
通过 Vue 的响应式系统,组件间共享 ref 对象来实现状态同步。 CalendarRoot.vue:15-16 当一个组件修改共享状态时,所有依赖该状态的组件会自动更新。
type CalendarRootContext = {
locale: Ref<string>
modelValue: Ref<DateValue | DateValue[] | undefined> // 响应式状态
placeholder: Ref<DateValue>
pagedNavigation: Ref<boolean>
preventDeselect: Ref<boolean>
grid: Ref< Grid<DateValue>[]>
weekDays: Ref<string[]>
weekStartsOn: Ref<0 | 1 | 2 | 3 | 4 | 5 | 6>
weekdayFormat: Ref<WeekDayFormat>
fixedWeeks: Ref<boolean>
multiple: Ref<boolean>
numberOfMonths: Ref<number>
disabled: Ref<boolean>
readonly: Ref<boolean>
initialFocus: Ref<boolean>
onDateChange: (date: DateValue) => void
onPlaceholderChange: (date: DateValue) => void
fullCalendarLabel: Ref<string>
parentElement: Ref<HTMLElement | undefined>
headingValue: Ref<string>
isInvalid: Ref<boolean>
isDateDisabled: Matcher
isDateSelected: Matcher
isDateUnavailable?: Matcher
isOutsideVisibleView: (date: DateValue) => boolean
prevPage: (prevPageFunc?: (date: DateValue) => DateValue) => void
nextPage: (nextPageFunc?: (date: DateValue) => DateValue) => void
isNextButtonDisabled: (nextPageFunc?: (date: DateValue) => DateValue) => boolean
isPrevButtonDisabled: (prevPageFunc?: (date: DateValue) => DateValue) => boolean
formatter: Formatter
dir: Ref<Direction>
}
集合管理
某些组件使用集合模式来管理子项目的注册和通信。 ComboboxGroup.vue:32-38 子组件在挂载时注册到父组件的集合中,卸载时移除。
onMounted(() => {
if (!rootContext.allGroups.value.has(id))
rootContext.allGroups.value.set(id, new Set())
})
onUnmounted(() => {
rootContext.allGroups.value.delete(id)
})