Using numbers, i.e. keyCodes, as v-on modifiers (and defining custom aliases via config.keyCodes) is no longer supported.
Vue 2
Vue.config.keyCodes = { f1: 112 } <!-- keyCode --> <input v-on:keyup.13="submit" /> <!-- alias --> <input v-on:keyup.enter="submit" /> <!-- keyCode --> <input v-on:keyup.112="showHelpText" /> <!-- custom alias --> <input v-on:keyup.f1="showHelpText" />
Vue 3
<input v-on:keyup.enter="submit" /> <input v-on:keyup.f1="showHelpText" />
$on, $off and $once instance methods are removed. Component instances no longer implement the event emitter interface.
Vue 2
// eventBus.js const eventBus = new Vue() export default eventBus // ChildComponent.vue import eventBus from './eventBus' export default { mounted() { eventBus.$on('custom-event', () => { console.log('Custom event triggered!') }) }, beforeDestroy() { eventBus.$off('custom-event') } } // ParentComponent.vue import eventBus from './eventBus' export default { methods: { callGlobalCustomEvenet() { eventBus.$emit('custom-event') } } }
Vue 3
// There is no direct migration path. // Depending on the circumstances, there are various options: // - Props and events should be first choice for parent-child communication. // Siblings can communicate via their parent. // - Provide / inject allow a component to communicate with its slot contents. // This is useful for tightly-coupled components that are always used together. // It can also be used for long-distance communication between components. // where props need to be passed down through many levels of components that // don't need those props themselves. // - Prop drilling can also be avoided by refactoring to use slots. If an interim // component doesn't need the props then it might indicate a problem with // separation of concerns. Introducing a slot in that component allows the // parent to create the content directly, so that props can be passed without // the interim component needing to get involved. // - Global state management, such as Pinia.
filters are removed and no longer supported.
Vue 2
<!-- template --> <div>{{ accountBalance | currentUSD }}</div> // script export default { props: { accountBalance: { type: Number, required: true } }, filters: { currencyUSD(value) { return '$' + value } } }
Vue 3
<!-- template --> <div>{{ accountInUSD }}</div> // script export default { props: { accountBalance: { type: Number, required: true } }, computed: { accountInUSD() { return '$' + this.accountBalance } } }
Support for the inline-template feature has been removed.
Vue 2
<ChildComponent inline-template :msg="parentMsg"> {{ msg }} {{ childState }} </ChildComponent>
Vue 3
<!-- ParentComponent.vue --> <ChildComponent v-slot="{ childState }"> {{ parentMsg }} {{ childState }} </ChildComponent> <!-- ChildComponent.vue --> <template> <slot :childState="childState" /> </template>
The $children instance property has been removed and is no longer supported.
Vue 2
<!-- template --> <div> <my-button>Change logo</my-button> </div> // script import MyButton from './MyButton' export default { components: { MyButton }, mounted() { console.log(this.$children) } }
Vue 3
<!-- template --> <div> <my-button ref="buttonRef">Change logo</my-button> </div> // script import { ref, onMounted } from 'vue' import MyButton from './MyButton' export default { components: { MyButton }, setup() { const buttonRef = ref(null) onMounted(() => { console.log(buttonRef.value) }) return { buttonRef } } }
The propsData option, used to pass props to the Vue instance during its creation, is removed.
Vue 2
const Comp = Vue.extend({ props: ['username'], template: '<div>{{ username }}</div>' }) new Comp({ propsData: { username: 'Evan } })
Vue 3
const app = createApp( { props: ['username'], template: '<div>{{ username }}</div> }, { username: 'Evan' } )