Vue3 script setup

201 阅读2分钟

以下是 Vue3 <script setup>超详细说明,涵盖核心机制、使用场景和最佳实践:


1. 核心设计原理

  • 编译时语法糖<script setup> 会在编译阶段转换为标准的 setup() 函数,所有顶层绑定自动暴露给模板。
  • 作用域隔离:内部代码默认在闭包中执行,避免污染全局作用域,同时通过编译器静态分析实现模板直接引用。

2. 响应式数据管理

  • 自动解包ref 在模板中无需 .value,但在逻辑代码中仍需:
    <script setup>
    const count = ref(0) // 模板中直接写 {{ count }}
    console.log(count.value) // JS 中需 .value
    </script>
    
  • 响应式工具链:支持 reactivecomputedwatch 等组合式 API,与标准写法一致。

3. 组件通信

  • Props 声明:使用 defineProps 宏(支持运行时声明和 TypeScript 类型):
    <script setup>
    const props = defineProps({
      title: String,
      size: { type: Number, default: 10 }
    })
    // TS 写法
    defineProps<{ title: string; size?: number }>()
    </script>
    
  • 事件发射:通过 defineEmits
    <script setup>
    const emit = defineEmits(['submit'])
    // TS 写法
    const emit = defineEmits<{ (e: 'submit', id: number): void }>()
    </script>
    

4. 依赖注入

  • 直接使用 provide/inject
    <script setup>
    import { provide } from 'vue'
    provide('key', 'value')
    </script>
    

5. 生命周期钩子

  • 直接导入使用(如 onMounted):
    <script setup>
    import { onMounted } from 'vue'
    onMounted(() => console.log('组件挂载'))
    </script>
    

6. 动态组件与异步

  • 动态组件:通过 :is 绑定组件名或导入的组件对象:
    <script setup>
    import CompA from './CompA.vue'
    const current = shallowRef(CompA)
    </script>
    <template>
      <component :is="current" />
    </template>
    
  • 异步组件:配合 defineAsyncComponent
    <script setup>
    import { defineAsyncComponent } from 'vue'
    const AsyncComp = defineAsyncComponent(() => import('./Comp.vue'))
    </script>
    

7. 高级特性

  • 暴露组件实例:通过 defineExpose 暴露特定属性:
    <script setup>
    const a = 1
    defineExpose({ a }) // 父组件通过 ref 访问
    </script>
    
  • 属性透传:使用 useAttrs() 访问非 props 的 attribute:
    <script setup>
    import { useAttrs } from 'vue'
    const attrs = useAttrs()
    </script>
    

8. 与选项式 API 对比

场景<script setup> 方案选项式 API 方案
逻辑复用组合式函数Mixins
类型支持完整的 TS 推导有限支持
代码组织按功能聚合按选项分离
性能编译优化更高效需要运行时处理

9. 最佳实践

  1. 单一职责:将复杂逻辑拆分为组合式函数(如 useFetch())。
  2. 类型安全:优先使用 TypeScript 泛型(如 defineProps<{...}>())。
  3. 避免隐式依赖:显式导入工具函数而非依赖全局变量。