@pythoughts/vue-skills-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/index.mjs +139 -0
- package/package.json +34 -0
- package/skills/create-adaptable-composable/SKILL.md +76 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +350 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +346 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-debug-guides/SKILL.md +205 -0
- package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
- package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
- package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
- package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
- package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
- package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
- package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
- package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
- package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
- package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
- package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
- package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
- package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
- package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
- package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
- package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
- package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
- package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
- package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
- package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
- package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
- package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
- package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
- package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
- package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
- package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
- package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
- package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
- package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
- package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
- package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
- package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
- package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
- package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
- package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
- package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
- package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
- package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
- package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
- package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
- package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
- package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
- package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
- package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
- package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
- package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
- package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
- package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
- package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
- package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
- package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
- package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
- package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
- package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
- package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
- package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
- package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
- package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
- package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
- package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
- package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
- package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
- package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
- package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
- package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
- package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
- package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
- package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
- package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
- package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
- package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
- package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
- package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
- package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
- package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
- package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
- package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
- package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
- package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
- package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
- package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
- package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
- package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
- package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
- package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
- package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
- package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
- package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
- package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
- package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
- package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
- package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
- package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
- package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
- package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
- package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
- package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
- package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
- package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
- package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
- package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
- package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
- package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
- package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
- package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
- package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
- package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
- package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
- package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
- package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
- package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
- package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
- package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
- package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
- package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
- package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
- package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
- package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
- package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
- package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
- package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
- package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
- package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
- package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
- package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
- package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
- package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
- package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
- package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Forward Slots to Child Components Correctly
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Wrapper components that don't forward slots break slot functionality for consumers
|
|
5
|
+
type: best-practice
|
|
6
|
+
tags: [vue3, slots, component-composition, wrapper-components, slot-forwarding]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Forward Slots to Child Components Correctly
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - When creating wrapper components that enhance or extend other components, you need to forward slots from the parent to the wrapped child. Without proper slot forwarding, consumers of your wrapper cannot customize the inner component's slots.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use `v-for` with `$slots` to iterate over all provided slots
|
|
16
|
+
- [ ] Use dynamic slot names with `v-slot:[slotName]`
|
|
17
|
+
- [ ] Pass slot props through with `v-bind="slotProps"`
|
|
18
|
+
- [ ] Handle cases where slotProps might be undefined
|
|
19
|
+
|
|
20
|
+
**Basic Slot Forwarding Pattern:**
|
|
21
|
+
```vue
|
|
22
|
+
<!-- EnhancedButton.vue - Wrapper component -->
|
|
23
|
+
<script setup>
|
|
24
|
+
import BaseButton from './BaseButton.vue'
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div class="button-wrapper">
|
|
29
|
+
<BaseButton v-bind="$attrs">
|
|
30
|
+
<!-- Forward all slots to BaseButton -->
|
|
31
|
+
<template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
|
|
32
|
+
<slot :name="slotName" v-bind="slotProps ?? {}" />
|
|
33
|
+
</template>
|
|
34
|
+
</BaseButton>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Usage:**
|
|
40
|
+
```vue
|
|
41
|
+
<script setup>
|
|
42
|
+
import EnhancedButton from './EnhancedButton.vue'
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<!-- Slots pass through to BaseButton -->
|
|
47
|
+
<EnhancedButton>
|
|
48
|
+
<template #icon>
|
|
49
|
+
<IconCheck />
|
|
50
|
+
</template>
|
|
51
|
+
<template #default>
|
|
52
|
+
Click me
|
|
53
|
+
</template>
|
|
54
|
+
</EnhancedButton>
|
|
55
|
+
</template>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Handling Scoped Slots
|
|
59
|
+
|
|
60
|
+
When the child component provides slot props, you must forward them:
|
|
61
|
+
|
|
62
|
+
```vue
|
|
63
|
+
<!-- DataTableWrapper.vue -->
|
|
64
|
+
<script setup>
|
|
65
|
+
import DataTable from './DataTable.vue'
|
|
66
|
+
|
|
67
|
+
const props = defineProps(['data'])
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div class="table-container">
|
|
72
|
+
<DataTable :items="data">
|
|
73
|
+
<!-- Forward slots including scoped slot props -->
|
|
74
|
+
<template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
|
|
75
|
+
<slot :name="slotName" v-bind="slotProps ?? {}" />
|
|
76
|
+
</template>
|
|
77
|
+
</DataTable>
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```vue
|
|
83
|
+
<!-- Consumer can use scoped slot props -->
|
|
84
|
+
<DataTableWrapper :data="users">
|
|
85
|
+
<template #row="{ item, index }">
|
|
86
|
+
<tr>
|
|
87
|
+
<td>{{ index + 1 }}</td>
|
|
88
|
+
<td>{{ item.name }}</td>
|
|
89
|
+
</tr>
|
|
90
|
+
</template>
|
|
91
|
+
</DataTableWrapper>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Alternative: Handling Undefined slotProps
|
|
95
|
+
|
|
96
|
+
Some scenarios require checking if slotProps exists:
|
|
97
|
+
|
|
98
|
+
```vue
|
|
99
|
+
<template>
|
|
100
|
+
<ChildComponent>
|
|
101
|
+
<template v-for="(_, name) in $slots" v-slot:[name]="slotProps">
|
|
102
|
+
<!-- Handle both scoped and non-scoped slots -->
|
|
103
|
+
<slot v-if="slotProps" :name="name" v-bind="slotProps" />
|
|
104
|
+
<slot v-else :name="name" />
|
|
105
|
+
</template>
|
|
106
|
+
</ChildComponent>
|
|
107
|
+
</template>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Forwarding Specific Slots Only
|
|
111
|
+
|
|
112
|
+
If you only want to forward certain slots:
|
|
113
|
+
|
|
114
|
+
```vue
|
|
115
|
+
<template>
|
|
116
|
+
<ChildComponent>
|
|
117
|
+
<!-- Only forward header and footer slots -->
|
|
118
|
+
<template v-if="$slots.header" #header="slotProps">
|
|
119
|
+
<slot name="header" v-bind="slotProps ?? {}" />
|
|
120
|
+
</template>
|
|
121
|
+
|
|
122
|
+
<template v-if="$slots.footer" #footer="slotProps">
|
|
123
|
+
<slot name="footer" v-bind="slotProps ?? {}" />
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<!-- Default slot handled differently -->
|
|
127
|
+
<slot />
|
|
128
|
+
</ChildComponent>
|
|
129
|
+
</template>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Common Mistakes
|
|
133
|
+
|
|
134
|
+
| Mistake | Problem | Solution |
|
|
135
|
+
|---------|---------|----------|
|
|
136
|
+
| Not using `v-bind="slotProps"` | Scoped slot data lost | Always bind slotProps |
|
|
137
|
+
| Forgetting `?? {}` or null check | Error when slotProps undefined | Add nullish coalescing |
|
|
138
|
+
| Static slot names in loop | Only forwards one slot | Use `v-slot:[slotName]` dynamic syntax |
|
|
139
|
+
| Missing `v-for` key warning | Vue warning (non-critical) | Keys not needed for slot functions |
|
|
140
|
+
|
|
141
|
+
## Reference
|
|
142
|
+
- [Vue Land FAQ - Forwarding Slots](https://vue-land.github.io/faq/forwarding-slots)
|
|
143
|
+
- [Vue.js Slots - Scoped Slots](https://vuejs.org/guide/components/slots.html#scoped-slots)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Non-Template Content Is Implicitly Default Slot Content
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Unexpected content placement when mixing named slots with loose content
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, slots, named-slots, default-slot, implicit-behavior]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Non-Template Content Is Implicitly Default Slot Content
|
|
10
|
+
|
|
11
|
+
**Impact: LOW** - When using named slots, any top-level content not wrapped in a `<template>` tag is automatically treated as default slot content. This implicit behavior can cause confusion about where content will render.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Understand that loose content goes to the default slot
|
|
16
|
+
- [ ] Use explicit `<template #default>` when clarity matters
|
|
17
|
+
- [ ] Keep slot content organization intentional
|
|
18
|
+
|
|
19
|
+
**The Implicit Behavior:**
|
|
20
|
+
```vue
|
|
21
|
+
<script setup>
|
|
22
|
+
import BaseLayout from './BaseLayout.vue'
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<BaseLayout>
|
|
27
|
+
<template #header>
|
|
28
|
+
<h1>Page Title</h1>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<!-- These are IMPLICITLY in the default slot -->
|
|
32
|
+
<p>First paragraph of main content.</p>
|
|
33
|
+
<p>Second paragraph of main content.</p>
|
|
34
|
+
|
|
35
|
+
<template #footer>
|
|
36
|
+
<p>Footer content</p>
|
|
37
|
+
</template>
|
|
38
|
+
</BaseLayout>
|
|
39
|
+
</template>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The two `<p>` elements are automatically placed in `<slot>` (the default slot) in the child component.
|
|
43
|
+
|
|
44
|
+
**Equivalent Explicit Version:**
|
|
45
|
+
```vue
|
|
46
|
+
<template>
|
|
47
|
+
<BaseLayout>
|
|
48
|
+
<template #header>
|
|
49
|
+
<h1>Page Title</h1>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<!-- Explicit default slot -->
|
|
53
|
+
<template #default>
|
|
54
|
+
<p>First paragraph of main content.</p>
|
|
55
|
+
<p>Second paragraph of main content.</p>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<template #footer>
|
|
59
|
+
<p>Footer content</p>
|
|
60
|
+
</template>
|
|
61
|
+
</BaseLayout>
|
|
62
|
+
</template>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## When Implicit Behavior Causes Confusion
|
|
66
|
+
|
|
67
|
+
**Scattered Content:**
|
|
68
|
+
```vue
|
|
69
|
+
<template>
|
|
70
|
+
<BaseLayout>
|
|
71
|
+
<template #header>
|
|
72
|
+
<h1>Title</h1>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<p>Content A</p> <!-- Goes to default slot -->
|
|
76
|
+
|
|
77
|
+
<template #sidebar>
|
|
78
|
+
<nav>Navigation</nav>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<p>Content B</p> <!-- Also goes to default slot! -->
|
|
82
|
+
|
|
83
|
+
<template #footer>
|
|
84
|
+
<p>Footer</p>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
<p>Content C</p> <!-- Also goes to default slot! -->
|
|
88
|
+
</BaseLayout>
|
|
89
|
+
</template>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
All three `<p>` elements end up in the default slot together, which may not be the intended order or grouping.
|
|
93
|
+
|
|
94
|
+
**Clearer with Explicit Default:**
|
|
95
|
+
```vue
|
|
96
|
+
<template>
|
|
97
|
+
<BaseLayout>
|
|
98
|
+
<template #header>
|
|
99
|
+
<h1>Title</h1>
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<template #default>
|
|
103
|
+
<p>Content A</p>
|
|
104
|
+
<p>Content B</p>
|
|
105
|
+
<p>Content C</p>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<template #sidebar>
|
|
109
|
+
<nav>Navigation</nav>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<template #footer>
|
|
113
|
+
<p>Footer</p>
|
|
114
|
+
</template>
|
|
115
|
+
</BaseLayout>
|
|
116
|
+
</template>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Best Practices
|
|
120
|
+
|
|
121
|
+
| Scenario | Recommendation |
|
|
122
|
+
|----------|---------------|
|
|
123
|
+
| Only default slot used | Implicit is fine |
|
|
124
|
+
| Mixed named + default slots | Consider explicit `#default` |
|
|
125
|
+
| Complex layouts | Always use explicit templates |
|
|
126
|
+
| Team/shared codebase | Prefer explicit for clarity |
|
|
127
|
+
|
|
128
|
+
## The Child Component
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<!-- BaseLayout.vue -->
|
|
132
|
+
<template>
|
|
133
|
+
<div class="layout">
|
|
134
|
+
<header>
|
|
135
|
+
<slot name="header"></slot>
|
|
136
|
+
</header>
|
|
137
|
+
|
|
138
|
+
<aside>
|
|
139
|
+
<slot name="sidebar"></slot>
|
|
140
|
+
</aside>
|
|
141
|
+
|
|
142
|
+
<main>
|
|
143
|
+
<!-- All implicit content ends up here -->
|
|
144
|
+
<slot></slot>
|
|
145
|
+
</main>
|
|
146
|
+
|
|
147
|
+
<footer>
|
|
148
|
+
<slot name="footer"></slot>
|
|
149
|
+
</footer>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Reference
|
|
155
|
+
- [Vue.js Slots - Named Slots](https://vuejs.org/guide/components/slots.html#named-slots)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Slot Name is Reserved and Not Included in Slot Props
|
|
3
|
+
impact: LOW
|
|
4
|
+
impactDescription: Expecting 'name' in scoped slot props when it's reserved causes confusion
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, slots, scoped-slots, reserved-props, naming]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Slot Name is Reserved and Not Included in Slot Props
|
|
10
|
+
|
|
11
|
+
**Impact: LOW** - When using scoped slots, the `name` attribute on the `<slot>` element is reserved for identifying the slot. It is not passed as part of the slot props to the parent component.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Don't expect `name` in slot props - it's reserved
|
|
16
|
+
- [ ] Use a different prop name if you need to pass a name value
|
|
17
|
+
- [ ] Remember only explicitly bound attributes become slot props
|
|
18
|
+
|
|
19
|
+
**Incorrect Expectation:**
|
|
20
|
+
```vue
|
|
21
|
+
<!-- ChildComponent.vue -->
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<slot name="header" title="Welcome"></slot>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```vue
|
|
30
|
+
<!-- ParentComponent.vue -->
|
|
31
|
+
<ChildComponent>
|
|
32
|
+
<template #header="props">
|
|
33
|
+
<!-- props = { title: "Welcome" } -->
|
|
34
|
+
<!-- 'name' is NOT included! -->
|
|
35
|
+
{{ props.name }} <!-- undefined -->
|
|
36
|
+
{{ props.title }} <!-- "Welcome" -->
|
|
37
|
+
</template>
|
|
38
|
+
</ChildComponent>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**If You Need to Pass a "Name" Value:**
|
|
42
|
+
```vue
|
|
43
|
+
<!-- ChildComponent.vue -->
|
|
44
|
+
<template>
|
|
45
|
+
<div>
|
|
46
|
+
<!-- Use a different prop name like 'slotName' or 'label' -->
|
|
47
|
+
<slot name="header" :label="slotLabel" :title="title"></slot>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script setup>
|
|
52
|
+
const slotLabel = 'header'
|
|
53
|
+
const title = 'Welcome'
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```vue
|
|
58
|
+
<!-- ParentComponent.vue -->
|
|
59
|
+
<ChildComponent>
|
|
60
|
+
<template #header="{ label, title }">
|
|
61
|
+
<h2>{{ title }}</h2>
|
|
62
|
+
<span>Section: {{ label }}</span>
|
|
63
|
+
</template>
|
|
64
|
+
</ChildComponent>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## What Gets Passed as Slot Props
|
|
68
|
+
|
|
69
|
+
| Attribute on `<slot>` | Passed to Parent? |
|
|
70
|
+
|----------------------|-------------------|
|
|
71
|
+
| `name` | No (reserved for slot identification) |
|
|
72
|
+
| `:text="message"` | Yes, as `text` |
|
|
73
|
+
| `:count="5"` | Yes, as `count` |
|
|
74
|
+
| `v-bind="object"` | Yes, spreads object properties |
|
|
75
|
+
| `class="..."` | No (not bound with `:`) |
|
|
76
|
+
|
|
77
|
+
## Multiple Named Slots Example
|
|
78
|
+
|
|
79
|
+
```vue
|
|
80
|
+
<!-- TabPanel.vue -->
|
|
81
|
+
<template>
|
|
82
|
+
<div class="tabs">
|
|
83
|
+
<slot name="tab1" :active="activeTab === 1" :label="'First Tab'"></slot>
|
|
84
|
+
<slot name="tab2" :active="activeTab === 2" :label="'Second Tab'"></slot>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<script setup>
|
|
89
|
+
import { ref } from 'vue'
|
|
90
|
+
const activeTab = ref(1)
|
|
91
|
+
</script>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```vue
|
|
95
|
+
<!-- Usage -->
|
|
96
|
+
<TabPanel>
|
|
97
|
+
<template #tab1="{ active, label }">
|
|
98
|
+
<!-- 'name' not available, but 'label' is -->
|
|
99
|
+
<button :class="{ active }">{{ label }}</button>
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<template #tab2="{ active, label }">
|
|
103
|
+
<button :class="{ active }">{{ label }}</button>
|
|
104
|
+
</template>
|
|
105
|
+
</TabPanel>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Reference
|
|
109
|
+
- [Vue.js Slots - Scoped Slots](https://vuejs.org/guide/components/slots.html#scoped-slots)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Explicit Default Template When Mixing Named and Scoped Slots
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Mixing v-slot on component with named slots inside causes ambiguous scope and compilation errors
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, slots, scoped-slots, named-slots, compilation-error]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Use Explicit Default Template When Mixing Named and Scoped Slots
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When a component uses both the default scoped slot and named slots, you must use an explicit `<template #default>` for the default slot. Using `v-slot` directly on the component while having nested named slot templates causes scope ambiguity and compilation errors.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] When using named slots alongside a default slot with props, always use explicit `<template #default>`
|
|
16
|
+
- [ ] Never mix `v-slot` on the component element with `<template #name>` inside
|
|
17
|
+
- [ ] Keep slot scope clear and unambiguous
|
|
18
|
+
|
|
19
|
+
**Incorrect:**
|
|
20
|
+
```vue
|
|
21
|
+
<script setup>
|
|
22
|
+
import MyComponent from './MyComponent.vue'
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<!-- BAD: v-slot on component + named template inside causes ambiguity -->
|
|
27
|
+
<MyComponent v-slot="{ message }">
|
|
28
|
+
<p>{{ message }}</p>
|
|
29
|
+
|
|
30
|
+
<template #footer>
|
|
31
|
+
<!-- Ambiguous: Is 'message' available here? Vue can't determine -->
|
|
32
|
+
<p>Footer: {{ message }}</p>
|
|
33
|
+
</template>
|
|
34
|
+
</MyComponent>
|
|
35
|
+
</template>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This causes a compilation error because Vue cannot determine:
|
|
39
|
+
1. Whether `message` from the default slot should be available in the footer slot
|
|
40
|
+
2. Which scope applies to the non-template content
|
|
41
|
+
|
|
42
|
+
**Correct:**
|
|
43
|
+
```vue
|
|
44
|
+
<script setup>
|
|
45
|
+
import MyComponent from './MyComponent.vue'
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<!-- GOOD: Explicit template for each slot with clear scope -->
|
|
50
|
+
<MyComponent>
|
|
51
|
+
<template #default="{ message }">
|
|
52
|
+
<p>{{ message }}</p>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<template #footer>
|
|
56
|
+
<!-- Clear: footer slot has its own scope, no access to default's 'message' -->
|
|
57
|
+
<p>Footer content here</p>
|
|
58
|
+
</template>
|
|
59
|
+
</MyComponent>
|
|
60
|
+
</template>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Correct - When Footer Also Has Props:**
|
|
64
|
+
```vue
|
|
65
|
+
<script setup>
|
|
66
|
+
import MyComponent from './MyComponent.vue'
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<MyComponent>
|
|
71
|
+
<template #default="{ message }">
|
|
72
|
+
<p>{{ message }}</p>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<template #footer="{ year }">
|
|
76
|
+
<!-- Each slot receives its own props -->
|
|
77
|
+
<p>Copyright {{ year }}</p>
|
|
78
|
+
</template>
|
|
79
|
+
</MyComponent>
|
|
80
|
+
</template>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## The Rule
|
|
84
|
+
|
|
85
|
+
When you have **any** named slots (`<template #name>`), always use explicit templates for **all** slots, including the default slot. This makes scope boundaries clear and prevents compilation errors.
|
|
86
|
+
|
|
87
|
+
| Pattern | Valid? | Notes |
|
|
88
|
+
|---------|--------|-------|
|
|
89
|
+
| `v-slot` on component only | Yes | Single default scoped slot |
|
|
90
|
+
| Named templates only | Yes | Multiple named slots |
|
|
91
|
+
| `v-slot` on component + named templates | No | Ambiguous scope |
|
|
92
|
+
| All explicit templates | Yes | Clear scope for each slot |
|
|
93
|
+
|
|
94
|
+
## Reference
|
|
95
|
+
- [Vue.js Slots - Named Scoped Slots](https://vuejs.org/guide/components/slots.html#named-scoped-slots)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Slot Content Only Has Access to Parent Component Scope
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Attempting to access child component data in slot content results in undefined values or errors
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, slots, scope, reactivity, common-mistake]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Slot Content Only Has Access to Parent Component Scope
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Slot content is compiled in the parent component's scope and cannot access data defined in the child component. This follows JavaScript's lexical scoping rules and is a common source of confusion.
|
|
12
|
+
|
|
13
|
+
When you provide content for a slot, that content is defined in your parent template and can only access data available in the parent component. The child component's internal state is not accessible unless explicitly passed via scoped slots.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Remember that slot content is compiled in parent scope
|
|
18
|
+
- [ ] Never try to access child component data directly in slot content
|
|
19
|
+
- [ ] Use scoped slots when child data needs to be exposed to parent
|
|
20
|
+
- [ ] Check that all template expressions reference data available in the current component
|
|
21
|
+
|
|
22
|
+
**Incorrect:**
|
|
23
|
+
```vue
|
|
24
|
+
<!-- Parent.vue -->
|
|
25
|
+
<script setup>
|
|
26
|
+
import SubmitButton from './SubmitButton.vue'
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<!-- BAD: Trying to access child's buttonText - this will be undefined -->
|
|
31
|
+
<SubmitButton>{{ buttonText }}</SubmitButton>
|
|
32
|
+
|
|
33
|
+
<!-- BAD: Trying to access child's isLoading state -->
|
|
34
|
+
<SubmitButton>
|
|
35
|
+
<span v-if="isLoading">Loading...</span>
|
|
36
|
+
<span v-else>Submit</span>
|
|
37
|
+
</SubmitButton>
|
|
38
|
+
</template>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<!-- SubmitButton.vue (Child) -->
|
|
43
|
+
<script setup>
|
|
44
|
+
import { ref } from 'vue'
|
|
45
|
+
|
|
46
|
+
const buttonText = ref('Click me') // Not accessible in parent's slot content
|
|
47
|
+
const isLoading = ref(false) // Not accessible in parent's slot content
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<button>
|
|
52
|
+
<slot></slot>
|
|
53
|
+
</button>
|
|
54
|
+
</template>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Correct - Use Scoped Slots:**
|
|
58
|
+
```vue
|
|
59
|
+
<!-- SubmitButton.vue (Child) - Expose data via slot props -->
|
|
60
|
+
<script setup>
|
|
61
|
+
import { ref } from 'vue'
|
|
62
|
+
|
|
63
|
+
const buttonText = ref('Click me')
|
|
64
|
+
const isLoading = ref(false)
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<button>
|
|
69
|
+
<!-- Pass child data as slot props -->
|
|
70
|
+
<slot :text="buttonText" :loading="isLoading"></slot>
|
|
71
|
+
</button>
|
|
72
|
+
</template>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<!-- Parent.vue -->
|
|
77
|
+
<script setup>
|
|
78
|
+
import SubmitButton from './SubmitButton.vue'
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<!-- GOOD: Receive child data via scoped slot -->
|
|
83
|
+
<SubmitButton v-slot="{ text, loading }">
|
|
84
|
+
<span v-if="loading">Loading...</span>
|
|
85
|
+
<span v-else>{{ text }}</span>
|
|
86
|
+
</SubmitButton>
|
|
87
|
+
</template>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Correct - Use Parent Data:**
|
|
91
|
+
```vue
|
|
92
|
+
<!-- Parent.vue -->
|
|
93
|
+
<script setup>
|
|
94
|
+
import { ref } from 'vue'
|
|
95
|
+
import SubmitButton from './SubmitButton.vue'
|
|
96
|
+
|
|
97
|
+
// Define data in parent where slot content is compiled
|
|
98
|
+
const message = ref('Submit Form')
|
|
99
|
+
const isSubmitting = ref(false)
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<template>
|
|
103
|
+
<!-- GOOD: Using parent's own data in slot content -->
|
|
104
|
+
<SubmitButton>
|
|
105
|
+
<span v-if="isSubmitting">Processing...</span>
|
|
106
|
+
<span v-else>{{ message }}</span>
|
|
107
|
+
</SubmitButton>
|
|
108
|
+
</template>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## The Function Analogy
|
|
112
|
+
|
|
113
|
+
Think of slots as function parameters:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// Slot content is like a callback defined in parent scope
|
|
117
|
+
function Parent() {
|
|
118
|
+
const parentData = 'Hello'
|
|
119
|
+
|
|
120
|
+
// This callback can only see parentData, not childData
|
|
121
|
+
Child((slotProps) => {
|
|
122
|
+
return parentData + (slotProps?.text || '')
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function Child(slotCallback) {
|
|
127
|
+
const childData = 'World' // Not visible to callback
|
|
128
|
+
|
|
129
|
+
// Must explicitly pass data via slot props
|
|
130
|
+
return slotCallback({ text: childData })
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Reference
|
|
135
|
+
- [Vue.js Slots - Render Scope](https://vuejs.org/guide/components/slots.html#render-scope)
|