Skip to content
On this page

插槽

只有在组件内才算插槽,传入 createVnode 的第三个参数

插槽本质是一个对象函数,在 render 函数中找到对应的函数,然后执行
js
const MyComponent = {
  setup() {
        useLifycycle()
      return {
          title:"asdfasd"
      }
  },
  render(proxy) {
      return h(Fragment, [
          h('div', proxy.$slots.header('header')),
          h('div', proxy.$slots.default()),
          h('div', proxy.$slots.footer())
      ])
  }
}

render(h(MyComponent, {}, {
  default: () => h('div', 'default'),
  header: (title) => h('h1', title),
  footer: () => h('footer', 'footer')
}), app)

createVNode 如果传入了一个对象,就是插槽

js
function createVNode(type, props, children = null){
  if (children) {
    let type = 0;
    if (Array.isArray(children)) {
      type = ShapeFlags.ARRAY_CHILDREN;
    } else if (isObject(children)){
        type = ShapeFlags.SLOTS_CHILDREN; // $slots 可以获取到属性
    } else {
      type = ShapeFlags.TEXT_CHILDREN;
    }
    vnode.shapeFlag |= type;
  }
}

同时,在 🔗setupComponent 函数中,把 slot 挂载到 instance.slots

js
function initSlots(instance, children) {
  instance.slots = children
}

function setupComponent(instance){
  const publicProperties = {
    //...
    $slots: (instance) => instance.slots 
  };

  const setup = type.setup; 
  const setupResult = setup(instance.props, {
      // ...
      slots: instance.slots,  
    });
  initSlots(instance,children) 
}

render 中传递了instance.proxy

js
const subTree = instance.render.call(instance.proxy, instance.proxy);
patch(instance.subTree, subTree, container);

所以在下面的 render 函数中的 $slots 就是 instance.slots,也即传入的 对象函数

js
render(proxy) {
    return h(Fragment, [
        h('div', proxy.$slots.header('header')),
        h('div', proxy.$slots.default()),  
        h('div', proxy.$slots.footer())
    ])
}
对于作用域插槽,其实本质是一个回调函数的调用

编译代码

父元素使用,接收了一个形参叫count,一般情况下会使用解构

html
<template #header={count}>
</template>

子元素创建,传入了一个对象作为参数,现在只有一个count 属性