render函数里定义插槽和使用插槽
vue3中this.slots和vue2的区别
vue3:this.slots是一个{ [name: string]: (…args: any[]) => Array | undefined }的对象,每个具名插槽的内容都要通过函数调用。如v-slot:foo插槽分发的内容通过this.slots.foo( )返回
vue2:this.slots是一个{ [name: string]: ?Array }的对象,v-slot:foo的内容通过this.slots.foo来访问 , 而this.scopedSlots才是和vue3里的this.$slots作用一样.
定义插槽
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>
vue3 render函数小变动
Render function API?是不是感觉有点陌生?那恭喜你,这个改动不会对你这位 <template> 用户造成影响。
老规矩,上帝视角看一下:
h 需要从全局导入进来(不再是 render 函数的参数了) render 函数的参数改变了(为了在常规组件和函数组件中表现一致) VNodes 具备了扁平的属性结构
render函数的参数
2.x 这么写
在 Vue 2.x 的版本中,render 函数会以参数的形式自动接收 h 函数(aka:createElement):
export default { render(h) { return h('div'); } }
3.x 应该这么写
在即将到来的 Vue 3.x 版本中,h 函数需要手动从全局引入进来:
import { h } from 'vue'; export default { render() { return h('div'); } }
render函数签名
2.x 这么写
上面也提到了,2.x 的 render 函数会自动接收 h 作为参数:
export default { render(h) { return h('div'); } }
3.x 应该这么写
在 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属性格式
2.x 是这样的
domProps 是 VNode 属性中的一个[嵌套列表]:
{ class: ['button', 'confirm-button'], style: { color: 'red' }, attrs: { id: 'confirm' }, domProps: { innerHTML: '' }, on: { click: confirmCreate }, key: 'submit-button', }
3.x 中则是这样的
在 3.x 版本中,VNode 的所有属性都已经实现了[扁平化]的处理:
{ class: ['button', 'confirm-button'], style: { color: 'red' }, id: 'submit', innerHTML: '', onClick: confirmCreate, key: 'submit-button', }
其实我也很少用 render 函数,毕竟 template 还是蛮香的。
如果想要获得更多的详细信息,请去这里: v3.vuejs.org/guide/migration/render-function-api.html (目前还没有中文版)
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vue3中的render函数里定义插槽和使用插槽的详细内容...