Why vnode-util
vnode-util
is a collection of functions that can be used to manipulate Vue VNodes. They are intended to be used inside render()
functions. The most common use case would be manipulating an array of child VNodes returned by a slot:
<script>
export default {
render() {
const children = this.$slots.default()
// How can we change the VNodes in `children` here?
// ...
}
}
</script>
<script>
export default {
render() {
const children = this.$slots.default()
// How can we change the VNodes in `children` here?
// ...
}
}
</script>
Working with the array of children is sometimes relatively straightforward, but it can become complicated if the slotted content is using directives such as v-for
or v-if
. In particular, a v-for
will introduce a fragment VNode, which wraps around the VNodes that represent the components and elements generated by the v-for
.
In general, manipulating VNodes is quite difficult, but vnode-util
can help with some of the most common cases. The various helpers can be used to iterate over the 'top-level' child VNodes, including those wrapped in fragments. They can then be used to add or remove VNodes, or change the props of the existing VNodes.
An example of adding a CSS class
to the children in a slot:
import { h } from 'vue'
import { addProps } from 'vnode-util'
export default {
render() {
const children = addProps(this.$slots.default(), () => {
return {
class: 'my-child'
}
})
return h('div', children)
}
}
import { h } from 'vue'
import { addProps } from 'vnode-util'
export default {
render() {
const children = addProps(this.$slots.default(), () => {
return {
class: 'my-child'
}
})
return h('div', children)
}
}
An example of inserting an <hr>
between each of the children:
import { h } from 'vue'
import { betweenChildren } from 'vnode-util'
export default {
render() {
const children = betweenChildren(this.$slots.default(), () => h('hr'))
return h('div', children)
}
}
import { h } from 'vue'
import { betweenChildren } from 'vnode-util'
export default {
render() {
const children = betweenChildren(this.$slots.default(), () => h('hr'))
return h('div', children)
}
}
There are more detailed examples, with demos, later in the guide. The key thing to appreciate is that these components will work even if the slotted content is using directives like v-for
or v-if
. The helper functions will walk the tree of fragments created by v-for
and skip over the hidden comment nodes created by v-if
, yielding the component and element nodes that would typically be regarded as the 'direct' children.
Is manipulating VNodes like this actually a good idea? Probably not. Most of the time it'd be better to solve the problem some other way. But if you find yourself in one of those rare edge cases where you really do need to tweak VNodes then it's probably better to use a library to smooth over some of the problems for you.
vnode-util
doesn't replicate functionality that is already present in Vue itself. In particular, you should be familiar with isVNode()
and cloneVNode()
. That said, the helpers in vnode-util
are designed in such a way that those core functions are often unnecessary.