引言<<往期回顾>>
- vue3源码分析——rollup打包monorepo
- vue3源码分析——实现组件的挂载流程
- vue3源码分析——实现props,emit,事件处理等
正文在 模板中使用插槽的方式如下:
<todo-button>Add todo</todo-button>复制代码
在template中的内容最终会被complie成render函数,render函数里面会调用h函数转化成vnode,在vnode的使用方法如下:render() {return h(TodoButton, {}, this.$slots.default)},复制代码
看完slots的基本用法,一起来实现个slots,方便自己理解slots的原理哦!实现基本的用法使用slots的地方是this.slots,并且调用的属性是default,那么slots,并且调用的属性是default,那么slots则是一个对象,对象里面有插槽的名称,如果使用者没有传递,则可以通过default来进行访问 。
测试用例
attention!!! 由于测试的是dom,需要先写入html等,在这里需要先创建对应的节点
let AppElement: Element;beforeEach(() => {appElement = document.createElement('div');appElement.id = 'app';document.body.appendChild(appElement);})afterEach(() => {document.body.innerHTML = '';})复制代码
本案例的测试正式开始 test('test basic slots', () => { // 子组件Fooconst Foo = {name: 'Foo',render() {return h('div', { class: 'foo' }, [h('p', {}, this.count), renderSlots(this.$slots)]);}}const app = createApp({render() {return h('div', { class: 'container' }, [h(Foo, { count: 1 }, { default: h('div', { class: 'slot' }, 'slot1') }),h(Foo, { count: 2 }, { default: [h('p', { class: 'slot' }, 'slot2'), h('p', { class: 'slot' }, 'slot2')] }),])}})const appDoc = document.querySelector('#app')app.mount(appDoc);// 测试挂载的内容是否正确const container = document.querySelector('.container') as HTMLElement;expect(container.innerHTML).toBe('<div class="foo"><p>1</p><div><div class="slot">slot1</div></div></div><div class="foo"><p>2</p><div><p class="slot">slot2</p><p class="slot">slot2</p></div></div>')})复制代码
需求分析【vue3源码分析——实现slots】通过上面的测试用例,可以分析以下内容:- 父组件使用子组件传入插槽的方式是在h的第三个参数,并且传入的是一个对象,value的值可以是对象,或者是数组
- 子组件中使用插槽的时候,是在this.$slots中获取的
- 并且还实现了一个renderSlot的方法,renderSlot是将this.$slots调用h转变为vnode
- 需要在绑定在this上面,那就在setupStatefulComponent函数代理中加入判断,传入的$slots ;
- 判断$slot是否在组件的代理中,然后代理需要把slots绑定在instance上面并且绑定值的时候需要把传入的对象统一转成数组;
- renderSlot方法调用了h函数,把一个数据转成vnode
// 需要把$slots绑定在this上面,那就需要在代理里面在加入一个判断即可function setupStatefulComponent(instance: any) {// 代理组件的上下文instance.proxy = new Proxy({}, {get(target,key){// 省略其他else if(key in instance.slots){return instance.slots[key]}}})}// 接下里在instance上面加上slots属性export function setupComponent(instance) {// 获取props和childrenconst { props, children } = instance.vnode// 处理propsconst slots = {}for (const key in children) {slots[key] = Array.isArray(children[key]) ? children[key] : [children[key]]}instance.slots = slots// ……省略其他}// 最后还需要使用renderSlot函数export function renderSlots(slots) {const slot = slots['default']if (slot) {return createVNode('div', {}, slot)}}复制代码
通过上面的编码,测试用例就可以完美通关啦具名插槽具名插槽就是,插槽除了可以有多个,并且除了default外,可以加入其他的名字,具体请看测试用例
测试用例
test('测试具名插槽', () => {const Foo = {name: 'Foo',render() {return h('div', { class: 'foo' },[renderSlots(this.$slots, 'header'),h('div', { class: 'default' }, 'default'),renderSlots(this.$slots, 'footer')]);}}const app = createApp({name: 'App',render() {return h('div', { class: 'container' }, [h(Foo, {}, {header: h('h1', {}, 'header'),footer: h('p', {}, 'footer')})])}})const appDoc = document.querySelector('#app')app.mount(appDoc);const container = document.querySelector('.container') as HTMLElementexpect(container.innerHTML).toBe('<div class="foo"><div><h1>header</h1></div><div class="default">default</div><div><p>footer</p></div></div>')})复制代码
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一个开箱即用的中后台前端框架,基于vue3+vite2开发
- 梦的分析属于潜意识,梦属于潜意识-
- 杜宾犬好养吗-杜宾犬优缺点分析,新手养杜宾犬需要注意什么-
- 智能手机|年轻人为何换不动手机了?背后原因分析
- 幻乐之城收视群体,幻乐之城栏目分析-
- 明年猪价行情分析,看看今年的猪价如何-
- 苹果|高通情何以堪!分析称苹果自研M系CPU碾压同行 至少领先三年
- SEO外链自动发布外链工具网站源码|seo外链推广免费源码
- 临渊而立影评,临渊而立完整剧情分析-
- 杭州杀妻碎尸案案件分析,杭州杀妻碎尸作案过程-