关于vue渲染函数中slot的应用
基于vue3创建的示例:
1. 创建一个Child.js文件为子组件:
1 // 子组件 Child.js 2 import { h, reactive, toRefs } from '@vue/runtime-core'; 3 export default { 4 props: { 5 book: { 6 type: String, 7 default: 'vue', 8 }, 9 version: { 10 type: Number, 11 default: 1, 12 }, 13 user: { 14 type: String, 15 default: 'engineeer', 16 }, 17 }, 18 emit: ['ChildClick'], 19 setup(props, context) { 20 // 将props中的属性转换为响应式ref对象, 在setup中读取时,使用prop.value取值,eg:book.value 21 const { book, version, user } = toRefs(props); 22 // 生成响应式reactive对象 23 const info = reactive({ 24 user, 25 }); 26 // 必须返回对象或者函数 27 return () => 28 h( 29 'div', 30 { 31 style: { height: '500px', backgroundColor: 'yellow !important' }, 32 class: { 33 foo: true, 34 bar: false, 35 }, 36 onClick() { 37 // setup中的渲染函数中的emit的写法 38 context.emit('ChildClick'); 39 }, 40 }, 41 [ 42 h('h1', 'Vue3渲染函数式组件应用'), 43 `BOOK: 《${book.value}》`, 44 // setup中this不是当前实例的引用,但slots等属性可以通过setup的第二个参数(当前是context对象)获取 45 context.slots.header({ version: version.value }), 46 context.slots.main({ user: info.user }), 47 context.slots.default(), // 子组件这样写必须要父组件有插槽内容,否则会报错 48 context.slots.footer(), 49 context.slots.specialSlot({ a: 1, b: 2, c: 3 }), 50 ] 51 ); 52 }, 53 };
2. 创建一个Father.vue的文件为父组件:
1 <script> 2 // Father.vue ===> 可以直接在js文件中创建(Father.js) 3 import Child from './reder-components/Child'; 4 import { h, resolveComponent } from 'vue'; 5 6 export default { 7 components: { 8 Child, 9 }, 10 data() { 11 return { 12 content: '字符串node', 13 num: 1, 14 }; 15 }, 16 render() { 17 // 读取组件 18 const Child = resolveComponent('Child'); 19 return h( 20 // {String | Object | Function} tag 21 // 一个 HTML 标签名、一个组件、一个异步组件、或一个函数式组件。 22 // 必需的。 23 'div', 24 // {Object} props 25 // 与 attribute、prop 和事件相对应的对象。我们会在模板中使用。 26 // 可选的。 27 { 28 style: { width: '100%', height: '1000px' }, 29 class: { 30 foo: true, 31 bar: false, 32 }, 33 }, 34 // {String | Array | Object} children 35 // 子 VNodes, 使用 `h()` 构建,或使用字符串获取 "文本 Vnode" 或者有插槽的对象。 36 // 可选的。 37 [ 38 h( 39 Child, 40 { 41 // props 42 book: '前端框架之学不动了也得学系列', 43 version: this.num, 44 user: 'Front-end Engineeer', 45 onChildClick: () => { 46 this.num += 1; 47 console.log('this.num+++++', this.num); 48 // 49 } 50 }, 51 // 在render函数中使用插槽的写法,通过在对象中使用键值对的方式使用 52 { 53 header: (props) => { 54 // 作用域插槽在渲染函数中的应用 55 return h('div', `VERSION:${props.version}`); 56 }, 57 main: ({ user }) => { 58 // 作用域插槽解构赋值方式 59 return h('div', `USER:${user}`); 60 }, 61 default: () => { 62 // 一般插槽在渲染函数中的应用 63 return h( 64 'div', 65 { 66 class: 'default_css', 67 }, 68 '应用于Child组件的默认插槽内容' 69 ); 70 }, 71 // 插槽函数,引用这个组件时可以使用具名插槽的方式(#footer)插入内容 72 footer: this.$slots.footer || '具名插槽占位符', // 这里最好使用函数形式 73 // 如果我们需要以某种方式对插槽进行操作,那么我们需要用一个新的函数来包裹它 74 specialSlot: (props) => { 75 // 在作用域插槽内部加入插槽函数,当前组件的父组件通过(#default="props")的方式使用子组件中的数据 76 const children = this.$slots.default 77 ? this.$slots.default(props) 78 : []; 79 return children.concat(h('div', 'Extra child')); 80 }, 81 } 82 ), 83 // 通过h()构建的子节点 84 h('h1', 'A headline'), 85 // 一般的字符串子节点 86 this.content, 87 // 在render函数中创建插槽,在数组中用this.$slots.插槽名(具名插槽对象,可选)的方式创建 88 this.$slots.some? this.$slots.some() : h('div', '默认this.$slots.some()字符串'), 89 ] 90 ); 91 }, 92 }; 93 </script> 94 95 <style lang="less"> 96 .default_css { 97 background-color: red; 98 } 99 .foo { 100 background-color: skyblue !important; 101 } 102 </style>
3. 对于Father.vue组件的引用:
1 <template> 2 <div> 3 <Father> 4 <template #footer> 5 <div>插槽footer++++++</div> 6 </template> 7 <template #default="{ a, b, c }"> 8 插槽default+++++ 9 <div>{{ a }} + {{ b }} + {{ c }} = {{ a + b + c }}</div> 10 </template> 11 <template #some> 12 <div>插槽some++++++</div> 13 </template> 14 </Father> 15 </div> 16 </template>
参考文档:vue之渲染函数。