--- /dev/null
+import { isArray } from '@vue/shared/src'
+import { ObjectDirective, DirectiveHook } from '../directives'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
+
+export interface LegacyDirective {
+ bind?: DirectiveHook
+ inserted?: DirectiveHook
+ update?: DirectiveHook
+ componentUpdated?: DirectiveHook
+ unbind?: DirectiveHook
+}
+
+const legacyDirectiveHookMap: Partial<
+ Record<
+ keyof ObjectDirective,
+ keyof LegacyDirective | (keyof LegacyDirective)[]
+ >
+> = {
+ beforeMount: 'bind',
+ mounted: 'inserted',
+ updated: ['update', 'componentUpdated'],
+ unmounted: 'unbind'
+}
+
+export function mapCompatDirectiveHook(
+ name: keyof ObjectDirective,
+ dir: ObjectDirective & LegacyDirective
+): DirectiveHook | DirectiveHook[] | undefined {
+ const mappedName = legacyDirectiveHookMap[name]
+ if (mappedName) {
+ if (isArray(mappedName)) {
+ const hook: DirectiveHook[] = []
+ mappedName.forEach(name => {
+ const mappedHook = dir[name]
+ if (mappedHook) {
+ __DEV__ &&
+ warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+ hook.push(mappedHook)
+ }
+ })
+ return hook.length ? hook : undefined
+ } else {
+ if (__DEV__ && dir[mappedName]) {
+ warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+ }
+ return dir[mappedName]
+ }
+ }
+}
OPTIONS_BEFORE_DESTROY,
OPTIONS_DESTROYED,
- PROPS_DEFAULT_THIS
+ PROPS_DEFAULT_THIS,
+
+ CUSTOM_DIR
}
type DeprecationData = {
`props default value function no longer has access to "this". ` +
`(found in prop "${key}")`,
link: `https://v3.vuejs.org/guide/migration/props-default-this.html`
+ },
+
+ [DeprecationTypes.CUSTOM_DIR]: {
+ message: (legacyHook: string, newHook: string) =>
+ `Custom directive hook "${legacyHook}" has been removed. ` +
+ `Use "${newHook}" instead.`,
+ link: `https://v3.vuejs.org/guide/migration/custom-directives.html`
}
}
import { warnDeprecation, DeprecationTypes } from './deprecations'
import { version } from '..'
import { LegacyConfig } from './globalConfig'
+import { LegacyDirective } from './customDirective'
/**
* @deprecated the default `Vue` export has been removed in Vue 3. The type for
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
const app = createApp(options)
+ // copy over asset registries and deopt flag
+ ;['mixins', 'components', 'directives', 'deopt'].forEach(key => {
+ // @ts-ignore
+ app._context[key] = singletonApp._context[key]
+ })
+
// copy over global config mutations
isCopyingConfig = true
for (const key in singletonApp.config) {
return Vue
}
- Vue.component = ((name: string, comp: any) => {
+ Vue.component = ((name: string, comp: Component) => {
if (comp) {
singletonApp.component(name, comp)
return Vue
}
}) as any
- Vue.directive = ((name: string, dir: any) => {
+ Vue.directive = ((name: string, dir: Directive | LegacyDirective) => {
if (dir) {
- singletonApp.directive(name, dir)
+ singletonApp.directive(name, dir as Directive)
return Vue
} else {
return singletonApp.directive(name)
import { currentRenderingInstance } from './componentRenderContext'
import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
import { ComponentPublicInstance } from './componentPublicInstance'
+import { mapCompatDirectiveHook } from './compat/customDirective'
export interface DirectiveBinding<V = any> {
instance: ComponentPublicInstance | null
if (oldBindings) {
binding.oldValue = oldBindings[i].value
}
- const hook = binding.dir[name] as DirectiveHook | undefined
+ let hook = binding.dir[name] as DirectiveHook | DirectiveHook[] | undefined
+ if (__COMPAT__ && !hook) {
+ hook = mapCompatDirectiveHook(name, binding.dir)
+ }
if (hook) {
callWithAsyncErrorHandling(hook, instance, ErrorCodes.DIRECTIVE_HOOK, [
vnode.el,