first
This commit is contained in:
247
.cursor/skills/vue/references/features-script-setup.md
Normal file
247
.cursor/skills/vue/references/features-script-setup.md
Normal file
@@ -0,0 +1,247 @@
|
||||
---
|
||||
name: script-setup
|
||||
description: Compile-time syntactic sugar for Composition API in SFCs
|
||||
---
|
||||
|
||||
# Script Setup
|
||||
|
||||
`<script setup>` is the recommended syntax for Composition API in Single-File Components.
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button @click="increment">{{ count }}</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
- Less boilerplate (no `export default`, no `return`)
|
||||
- TypeScript type inference
|
||||
- Better runtime performance
|
||||
- Better IDE support
|
||||
|
||||
## Top-Level Bindings
|
||||
|
||||
All top-level bindings are automatically available in template:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// Variables
|
||||
const msg = 'Hello'
|
||||
|
||||
// Imports
|
||||
import { capitalize } from './helpers'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
// Functions
|
||||
function greet() {
|
||||
console.log(msg)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MyComponent />
|
||||
<p>{{ capitalize(msg) }}</p>
|
||||
<button @click="greet">Greet</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Compiler Macros
|
||||
|
||||
These are available without import:
|
||||
|
||||
- `defineProps()` - declare props
|
||||
- `defineEmits()` - declare emits
|
||||
- `defineModel()` - declare v-model (3.4+)
|
||||
- `defineExpose()` - expose public instance properties
|
||||
- `defineOptions()` - declare component options (3.3+)
|
||||
- `defineSlots()` - type slot props (3.3+)
|
||||
- `withDefaults()` - provide prop defaults
|
||||
|
||||
## Using Components
|
||||
|
||||
Import and use directly without registration:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import MyComponent from './MyComponent.vue'
|
||||
import { MyButton } from './components'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MyComponent />
|
||||
<MyButton />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Dynamic Components
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import Foo from './Foo.vue'
|
||||
import Bar from './Bar.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="condition ? Foo : Bar" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Recursive Components
|
||||
|
||||
SFCs can reference themselves by filename:
|
||||
|
||||
```vue
|
||||
<!-- FooBar.vue can use <FooBar/> in its template -->
|
||||
```
|
||||
|
||||
## Custom Directives
|
||||
|
||||
Variables starting with `v` are available as directives:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const vFocus = {
|
||||
mounted: (el: HTMLElement) => el.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input v-focus />
|
||||
</template>
|
||||
```
|
||||
|
||||
## defineExpose()
|
||||
|
||||
Components are closed by default. Use `defineExpose` to expose properties:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const count = ref(0)
|
||||
const publicMethod = () => console.log('called')
|
||||
|
||||
defineExpose({
|
||||
count,
|
||||
publicMethod
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
Parent can access via template ref:
|
||||
|
||||
```ts
|
||||
const childRef = ref()
|
||||
childRef.value.count // accessible
|
||||
childRef.value.publicMethod() // accessible
|
||||
```
|
||||
|
||||
## defineOptions() (3.3+)
|
||||
|
||||
Declare component options without separate `<script>` block:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
name: 'CustomName'
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## defineSlots() (3.3+)
|
||||
|
||||
Type slot props for IDE support:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const slots = defineSlots<{
|
||||
default(props: { msg: string }): any
|
||||
header(props: { title: string }): any
|
||||
}>()
|
||||
</script>
|
||||
```
|
||||
|
||||
## useSlots() & useAttrs()
|
||||
|
||||
Access slots and attrs in script:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { useSlots, useAttrs } from 'vue'
|
||||
|
||||
const slots = useSlots()
|
||||
const attrs = useAttrs()
|
||||
</script>
|
||||
```
|
||||
|
||||
## Top-Level await
|
||||
|
||||
Async setup with Suspense:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const data = await fetch('/api/data').then(r => r.json())
|
||||
</script>
|
||||
```
|
||||
|
||||
> Note: Requires `<Suspense>` boundary in parent.
|
||||
|
||||
## Generic Components (TypeScript)
|
||||
|
||||
```vue
|
||||
<script setup lang="ts" generic="T extends string | number">
|
||||
defineProps<{
|
||||
items: T[]
|
||||
selected: T
|
||||
}>()
|
||||
</script>
|
||||
```
|
||||
|
||||
Multiple generics with constraints:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts" generic="T extends Item, U extends string">
|
||||
import type { Item } from './types'
|
||||
|
||||
defineProps<{
|
||||
item: T
|
||||
label: U
|
||||
}>()
|
||||
</script>
|
||||
```
|
||||
|
||||
## Alongside Normal Script
|
||||
|
||||
For advanced cases like named exports or one-time side effects:
|
||||
|
||||
```vue
|
||||
<script lang="ts">
|
||||
// Runs once when module is imported
|
||||
runSideEffect()
|
||||
|
||||
export const exportedValue = 'hello'
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Runs for each component instance
|
||||
</script>
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vuejs.org/api/sfc-script-setup.html
|
||||
-->
|
||||
Reference in New Issue
Block a user