本文详解Vue 3中Render函数如何定义和使用插槽,对比Vue 2中slots对象结构的差异。重点解析h函数需从全局导入、render函数签名变化以及VNode属性扁平化处理,帮助开发者平滑迁移至Vue 3的渲染机制。
在Vue 3的Render函数中,插槽的定义与使用方式发生了显著变化,理解这些机制对于编写底层组件至关重要。
Vue 3中的this.slots对象结构与Vue 2存在本质区别,这直接影响了对插槽内容的访问方式。
在Vue 3中,this.slots是一个包含函数属性的对象,其类型为{ [name: string]: (…args: any[]) => Array | undefined }。这意味着每个具名插槽的内容都必须通过调用对应的函数来获取,例如名为foo的插槽,其分发内容需通过this.slots.foo()调用返回。
相比之下,Vue 2中this.slots是一个{ [name: string]: ?Array }类型的对象,直接通过this.slots.foo即可访问v-slot:foo的内容。而在Vue 2中,与Vue 3的this.$slots作用相似的是this.scopedSlots。
定义插槽时,需要明确如何访问静态内容。
使用this.$slots.[插槽名]可以访问一个返回VNode数组的函数,该函数用于获取静态插槽的内容。
const BlogPost = defineComponent({
render(){
return h('div', [
h('h1',this.$slots.header&&this.$slots.header()||'默认header插槽'),
h('p',this.$slots.default&&this.$slots.default({message:'我是作用域插槽的message'})||'默认default插槽'),
h('h4',this.$slots.footer&&this.$slots.footer()||'默认footer插槽'),
])
}
})
// 以上代码相当于以下的template
<template>
<div>
<h1>
<slot name="header">默认header插槽</slot>
</h1>
<p>
<slot>默认default插槽</slot>
</p>
<h4>
<slot name="footer">默认footer插槽</slot>
</h4>
</div>
</template>在定义包含插槽的组件时,需正确使用插槽传递内容。
在h函数的第三个参数中,可以使用{ [name: string]: (…args: any[]) => Array | undefined }形式的对象来定义组件的具体插槽内容,从而灵活控制插槽的行为。
const BlogPostWrapper = defineComponent({
render(){
return h('div',
{style:'background:skyblue'},
h(
BlogPost,
null,
{
header(props){
return '我是传进的header插槽内容'
},
default(props){
// 这里的props就是作用域插槽的插槽prop
return 'BlogPostWrapper的default插槽内容::>>'+props.message
},
footer(props){
return '我是传进的footer插槽内容'
}
}
)
)
}
})// 相当于template
<template>
<div>
<BlogPost>
<tempalte #header>'我是传进的header插槽内容'</tempalte>
<tempalte #default="props">
{{'BlogPostWrapper的default插槽内容::>>'+props.message}}
</tempalte>
<tempalte #footer>我是传进的footer插槽内容</tempalte>
</BlogPost>
</div>
</template>Vue 3的Render函数API进行了一些重要变动,了解这些变化有助于避免兼容性问题。
面对陌生的Render function API,使用<template>的用户无需担心,这些改动主要影响底层渲染逻辑。
从整体视角来看,主要变动包括以下几点:
h函数需要从全局导入,不再作为render函数的参数传递。render函数的参数结构发生了改变,旨在保持常规组件和函数组件行为的一致性。VNodes对象的属性结构实现了扁平化处理,简化了属性访问。
关于render函数的参数传递,不同版本间存在差异。
在Vue 2.x版本中,代码编写方式如下:
在Vue 2.x版本中,render函数会自动接收h函数(即createElement)作为参数:
export default {
render(h) {
return h('div');
}
}在Vue 3.x版本中,代码编写方式应调整为:
在Vue 3.x版本中,h函数需要手动从全局引入,不再由框架自动注入:
import { h } from 'vue';
export default {
render() {
return h('div');
}
}render函数的签名在Vue 3中发生了根本性变化。
在Vue 2.x版本中,render函数的写法如下:
如前所述,Vue 2.x的render函数会自动接收h作为其参数:
export default {
render(h) {
return h('div');
}
}在Vue 3.x版本中,render函数不再接收任何参数,其主要作用是在setup函数中使用。
在 Vue 3.x 版本中,render 函数不再接收任何参数,其主要作用是在 setup 函数中使用,以便方便获取作用域链中的响应式状态、各种函数以及传递给 setup 函数的参数。
import { h, reactive } from 'vue';
export default {
setup(props, { slots, attrs, emit }) {
const state = reactive({ count: 0 });
function increment() {
state.count++
}
// 返回一个 render 函数
return () => {
h(
'div',
{ onClick: increment, },
state.count,
)
}
}
}VNode的属性格式在Vue 3中进行了优化。
在Vue 2.x中,VNode属性的结构如下:
domProps是VNode属性中的一个嵌套列表,例如:
{
class: ['button', 'confirm-button'],
style: { color: 'red' },
attrs: { id: 'confirm' },
domProps: { innerHTML: '' },
on: { click: confirmCreate },
key: 'submit-button',
}在Vue 3.x中,VNode属性的结构调整为:
在Vue 3版本中,VNode的所有属性均实现了扁平化处理,例如:
{
class: ['button', 'confirm-button'],
style: { color: 'red' },
id: 'submit',
innerHTML: '',
onClick: confirmCreate,
key: 'submit-button',
}实际上,由于template模板更加直观易用,许多开发者较少直接使用render函数。
如需获取更多详细信息,可访问官方文档:v3.vuejs.org/guide/migration/render-function-api.html(目前尚无中文版)。
以上为个人经验总结,希望能为大家提供参考,也希望大家多多支持本站。