h is now globally imported instead of passed to render function as an argument.
Vue 2
export default {
render(h) {
return h('div')
}
}
Vue 3
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
VNodes now have a flat props structure.
Vue 2
{
staticClass: 'button',
class: { 'is-outlined': isOutlined },
staticStyle: { color: '#34495E' },
style: { backgroundColor: buttonColor },
attrs: { id: 'submit' },
domProps: { innerHTML: '' },
on: { click: submitForm },
key: 'submit-button'
}
Vue 3
{
class: ['button', { 'is-outlined': isOutlined }],
style: [{ color: '#34495E' }, { backgroundColor: buttonColor }]
id: 'submit',
innerHTML: '',
onClick: submitForm,
key: 'submit-button'
}
String ID can no longer be used to implicitly lookup registered components.
Vue 2
Vue.component('button-counter', {
data() {
return {
count: 0
}
}
template: `
<button @click="count++">
Clicker {{ count }} times.
</button>
`
})
export default {
render(h) {
return h('button-counter')
}
}
Vue 3
import { h, resolveComponent } from 'vue'
export default {
setup() {
const ButtonCounter = resolveComponent('button-counter')
return () => h(ButtonCounter)
}
}
Slots are defined as children of the current node as an object.
Vue 2
h(LayoutComponent, [
h('div', { slot: 'header' }, this.header),
h('div', { slot: 'content' }, this.content),
])
Vue 3
h(LayoutComponent, {}, {
header: () => h('div', this.header),
content: () => h('div', this.content),
})
Scoped slots are now unified into the $slots option.
Vue 2
this.$scopedSlots.header
Vue 3
$listeners object has been removed – event listeners are now part of $attrs.
Vue 2
<!-- template -->
<label>
<input type="text" v-bind="$attrs" v-on="$listeners" />
</label>
// script
export default {
inheritAttrs: false
}
Vue 3
<!-- template -->
<label>
<input type="text" v-bind="$attrs" />
</label>
// script
export default {
inheritAttrs: false
}
$attrs now contains all attributes passed to a component, including class and style.
Vue 2
<!-- ChildComponent.vue - template -->
<label>
<input type="text" v-bind="$attrs" />
</label>
// ChildComponent.vue - script
export default {
inheritAttrs: false
}
<!-- ParentComponent.vue - template -->
<ChildComponent id="my-id" class="my-class" />
<!-- output -->
<label class="my-class">
<input type="text" id="my-id" />
</label>
Vue 3
<!-- ChildComponent.vue - template -->
<label>
<input type="text" v-bind="$attrs" />
</label>
// ChildComponent.vue - script
export default {
inheritAttrs: false
}
<!-- ParentComponent.vue - template -->
<ChildComponent id="my-id" class="my-class" />
<!-- output -->
<label>
<input type="text" id="my-id" class="my-class" />
</label>