阿里云主机折上折
  • 微信号
Current Site:Index > The implementation principle of scoped slots

The implementation principle of scoped slots

Author:Chuan Chen 阅读数:21959人阅读 分类: Vue.js

Basic Concepts of Scoped Slots

Scoped slots allow child components to pass data to parent components, enabling the parent to determine how to render this data. This mechanism breaks the unidirectional data flow of traditional slots, achieving child-to-parent data communication. In Vue 3, scoped slots are implemented using the v-slot directive, relying on the underlying logic of render functions.

// Child component
const ChildComponent = {
  template: `
    <div>
      <slot :user="user" :age="age"></slot>
    </div>
  `,
  setup() {
    const user = ref('Alice')
    const age = ref(25)
    return { user, age }
  }
}

// Parent component usage
<ChildComponent v-slot="{ user, age }">
  <p>{{ user }} is {{ age }} years old</p>
</ChildComponent>

Compilation Phase Processing

When the Vue compiler encounters a scoped slot, it performs special processing. The template compiler converts the slot content into a render function while preserving references to the scoped data. This process primarily occurs in the @vue/compiler-sfc package.

For the example above, the compiled render function roughly looks like this:

// Compiled result of the child component
function render(_ctx, _cache) {
  return {
    type: 'div',
    children: [
      {
        type: 'slot',
        props: {
          user: _ctx.user,
          age: _ctx.age
        }
      }
    ]
  }
}

Runtime Implementation Mechanism

Vue 3's runtime core handles slots through the createSlots function. Scoped slots are converted into function forms that receive parameters and return VNodes. This process occurs in runtime-core/src/componentSlots.ts.

Key implementation code:

function createSlots(slots, dynamicSlots) {
  const slot = (props) => {
    return normalizeSlotValue(slots(props))
  }
  slot._ = 1 // Marks it as a scoped slot
  return slot
}

Data Propagation Path of Scoped Slots

The complete path of data propagation from child to parent components:

  1. The child component collects slot props when executing the render function.
  2. Exposes the slot function via setupContext.slots.
  3. The parent component passes props when calling the slot function.
  4. The slot content is rendered based on the props.
// Simplified runtime flow
const childVNode = {
  type: ChildComponent,
  children: {
    default: (props) => h('p', `${props.user} is ${props.age}`)
  }
}

// Execution inside the child component
const slots = childVNode.children
const slotContent = slots.default({ user: 'Alice', age: 25 })

Performance Differences Compared to Regular Slots

Scoped slots have additional performance overhead compared to regular slots:

  1. The slot function must be re-executed on each render.
  2. Dependency collection is more complex, requiring tracking of slot prop changes.
  3. Higher memory usage due to maintaining scope closures.

Vue 3 mitigates this overhead with the following optimizations:

  • Static hoisting of unchanged slot content during compilation.
  • Caching the results of slot function execution.
  • Reduced dependency tracking costs via the Proxy-based reactivity system.

Implementation of Dynamic Scoped Slots

Dynamic slot names can be combined with scoped slots for more flexible API design:

<template>
  <MyComponent>
    <template v-slot:[dynamicSlotName]="props">
      <p>{{ props.message }}</p>
    </template>
  </MyComponent>
</template>

<script setup>
const dynamicSlotName = ref('header')
</script>

The compiled code handles dynamic slot names:

function render(_ctx) {
  return h(MyComponent, null, {
    [_ctx.dynamicSlotName]: (props) => h('p', props.message)
  })
}

Type System for Scoped Slots

In TypeScript environments, Vue 3 provides robust type support. Generics and type inference ensure type safety for slot props:

// Child component defines prop types
defineComponent({
  slots: {
    default: (props: { user: string; age: number }) => VNode[]
  }
})

// Parent component gets type hints when using
<ChildComponent v-slot="{ user, age }">
  <!-- `user` and `age` have correct type inference -->
</ChildComponent>

Advanced Usage of Scoped Slots

Scoped slots can be nested to create complex component abstractions. For example, implementing a composable list component:

// List component
const List = {
  template: `
    <ul>
      <li v-for="(item, index) in items" :key="index">
        <slot :item="item" :index="index"></slot>
      </li>
    </ul>
  `,
  props: ['items']
}

// Composition usage
<List :items="users" v-slot="{ item, index }">
  <UserProfile :user="item" :rank="index + 1"/>
</List>

Comparison with React Render Props

Scoped slots are similar to React's render props pattern but have key differences:

  1. More concise syntax, directly integrated into templates.
  2. Support for multiple slots (named slots).
  3. Better type inference (in TypeScript).
  4. Deep integration with Vue's reactivity system.

Equivalent React implementation:

<List items={users}>
  {(item, index) => <UserProfile user={item} rank={index + 1} />}
</List>

Debugging Techniques for Scoped Slots

Use the following methods to debug scoped slot issues:

  1. Inspect the compiled render function.
  2. Use Vue DevTools to examine slot content.
  3. Add logs inside slot functions.
// Debugging example
<ChildComponent v-slot="props">
  {{ console.log('Slot props:', props) }}
  <!-- Content -->
</ChildComponent>

Application of Scoped Slots in Component Libraries

Modern UI libraries widely use scoped slots for flexibility. For example, customizing table cell rendering:

<DataTable :data="users">
  <template #name="{ value }">
    <span class="name-cell">{{ value.toUpperCase() }}</span>
  </template>
  <template #age="{ value }">
    <ProgressBar :value="value" max="100"/>
  </template>
</DataTable>

This pattern allows component libraries to provide structured UIs while letting users decide rendering details.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.