Vue 3 的 script setup 语法与普通 <script> 相比有哪些特性?

大白话 Vue 3 的 script setup 语法与普通

前端小伙伴们,有没有被Vue组件里的"样板代码"搞到想摔键盘?写个组件要export defaultsetup函数、return变量三件套,注册组件还要在components里列一遍,模板里用个变量还得先return出来……
今天咱们就聊聊Vue3的"代码减负神器"——script setup语法!用它写组件,就像吃了布洛芬,痛点瞬间缓解,代码量直接砍一半!看完这篇,你不仅能上手写,还能和面试官唠明白它的核心优势~

一、普通<script>的"三大痛点"

先讲个我上周改需求的经历:给客户做商品详情页,要加个PriceInfo组件显示价格。用普通<script>写,代码是这样的:

<!-- 普通<script>写法 -->
<script>
import { ref, computed } from 'vue';
import PriceTag from './PriceTag.vue'; // 引入子组件

export default {
  components: { PriceTag }, // 注册子组件(必须写!)
  props: {
    originalPrice: { type: Number, required: true },
    discount: { type: Number, default: 0 }
  },
  setup(props) {
    const finalPrice = computed(() => {
      return props.originalPrice * (1 - props.discount / 100);
    });
    // 必须return才能在模板中使用!
    return { finalPrice };
  }
};
</script>

<template>
  <div>
    <!-- 用子组件还得确保已注册 -->
    <PriceTag :price="finalPrice" />
  </div>
</template>

改需求时我发现:

  1. 重复代码多:每次都要写export defaultcomponents注册、setup函数和return
  2. 模板访问麻烦:变量必须return才能在模板用,漏了就报错;
  3. 类型声明冗余:用TS时,propsemit的类型要写两次(props选项+类型断言)。

二、技术原理:script setup的"代码瘦身逻辑"

script setup是Vue3推出的语法糖,目标是简化组合式API的使用,让组件代码更简洁、更直观。它的核心设计是:自动处理样板代码,让开发者专注业务逻辑

1. 自动暴露变量和函数

script setup中,声明的变量、函数、响应式对象会自动暴露给模板,无需手动return。就像给变量装了"传送门",模板里直接用!

2. 组件/指令自动注册

通过import引入的组件、自定义指令,会自动注册,无需在componentsdirectives选项中声明。告别"引入-注册-使用"的三步曲,直接引入就能用~

3. 更简洁的props/emit声明

script setup提供definePropsdefineEmit宏(编译器宏,无需导入),让propsemit的声明更简洁,且自动类型推导(配合TS更爽)。

4. 生命周期和组合式API直接使用

onMountedwatch等生命周期钩子,以及refreactive等组合式API,无需从setup函数内调用,直接在script setup顶层使用。

三、代码示例:从"繁琐"到"丝滑"的对比

示例1:基础变量与模板访问

普通<script>写法:
<script>
import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const increment = () => count.value++;
    // 必须return!
    return { count, increment };
  }
};
</script>

<template>
  <button @click="increment">点击次数:{{ count }}</button>
</template>
script setup写法:
<script setup>
import { ref } from 'vue';

// 直接声明变量,自动暴露给模板
const count = ref(0);
const increment = () => count.value++;
</script>

<template>
  <button @click="increment">点击次数:{{ count }}</button>
</template>

对比:少了export defaultsetup函数和return,代码量减少40%!

示例2:组件自动注册

普通<script>写法:
<script>
import PriceTag from './PriceTag.vue'; // 引入组件

export default {
  components: { PriceTag }, // 必须注册!
  setup() {
    return {};
  }
};
</script>

<template>
  <PriceTag /> <!-- 可用 -->
</template>
script setup写法:
<script setup>
import PriceTag from './PriceTag.vue'; // 引入即注册!
</script>

<template>
  <PriceTag /> <!-- 直接用,无需注册 -->
</template>

对比:省去components注册步骤,代码更清爽~

示例3:props与emit声明(含TS)

普通<script>+TS写法:
<script lang="ts">
import { defineComponent, PropType } from 'vue';

export default defineComponent({
  props: {
    // 类型需要同时声明在props选项和类型断言
    user: {
      type: Object as PropType<{ name: string; age: number }>,
      required: true
    }
  },
  emits: {
    'user-updated': (newUser: { name: string; age: number }) => true
  },
  setup(props, { emit }) {
    const updateUser = () => {
      emit('user-updated', { name: '新名字', age: 18 });
    };
    return { updateUser };
  }
});
</script>
script setup+TS写法:
<script setup lang="ts">
// defineProps和defineEmit是编译器宏,无需导入
const props = defineProps<{
  user: { name: string; age: number };
}>();

const emit = defineEmit<{
  (e: 'user-updated', newUser: { name: string; age: number }): void;
}>();

const updateUser = () => {
  emit('user-updated', { name: '新名字', age: 18 });
};
</script>

对比

  • defineProps直接通过类型声明props,无需重复写typePropType
  • defineEmit通过类型定义事件,自动推导参数类型;
  • 无需手动returnupdateUser自动暴露给模板。

示例4:生命周期与组合式API

普通<script>写法:
<script>
import { onMounted, ref } from 'vue';

export default {
  setup() {
    const data = ref(null);
    onMounted(() => {
      fetch('/api/data').then(res => res.json()).then(d => data.value = d);
    });
    return { data };
  }
};
</script>
script setup写法:
<script setup>
import { onMounted, ref } from 'vue';

const data = ref(null);
// 直接在顶层调用生命周期钩子
onMounted(() => {
  fetch('/api/data').then(res => res.json()).then(d => data.value = d);
});
</script>

对比:代码结构更扁平,逻辑更直观~

四、一张表看尽核心差异

对比项普通<script><script setup>
变量暴露需通过setupreturn暴露顶层声明的变量自动暴露给模板
组件注册需在components选项中手动注册import后自动注册(无需额外代码)
props声明需写props选项(类型冗余)defineProps宏(类型自动推导)
emit声明需写emits选项(类型冗余)defineEmit宏(类型自动推导)
生命周期调用需在setup函数内调用直接在顶层调用(更扁平)
代码量较多(样板代码多)减少约30%-50%(更简洁)
TS支持需手动类型断言(易出错)自动类型推导(更友好)
组合式API使用需在setup函数内组织直接顶层使用(逻辑更清晰)

五、面试题回答方法

正常回答(结构化):

“Vue3的<script setup>是为简化组合式API使用而设计的语法糖,核心特性包括:

  1. 自动暴露:顶层声明的变量、函数自动暴露给模板,无需return
  2. 自动注册import的组件/指令自动注册,无需components/directives选项;
  3. 简化props/emit:通过definePropsdefineEmit宏声明,支持类型自动推导;
  4. 更扁平的结构:生命周期钩子和组合式API可直接在顶层调用,无需嵌套在setup函数内;
  5. 更好的TS集成:通过类型声明自动推导props/emit类型,减少冗余代码。”

大白话回答(接地气):

<script setup>就像给Vue组件装了‘代码瘦身器’!以前写组件,得先export default,再在setup里写逻辑,最后return变量给模板——麻烦得很。现在用<script setup>,声明的变量直接‘传’到模板里,引入的组件不用手动注册,propsemitdefineProps/defineEmit一写,类型还能自动推导。就像以前做饭要洗锅、切菜、炒菜三步,现在直接给你个‘一键炒菜锅’,步骤少了,效率高了,代码还更清爽~”

六、总结:3个核心优势+2个使用建议

3个核心优势:

  1. 代码更简洁:减少export defaultcomponents注册、return等样板代码;
  2. 开发更高效:自动暴露、自动注册等特性让开发者专注业务逻辑;
  3. TS更友好defineProps/defineEmit的类型推导减少冗余声明,降低出错率。

2个使用建议:

  • 复杂组件仍可用普通<script>:如果需要使用mixinsextends等选项式API,或组件逻辑特别复杂(如需要访问this),普通<script>更灵活;
  • 配合unref简化模板:如果模板中频繁访问refvalue属性(如count.value),可以用const { count } = toRefs(props)const count = computed(() => props.count)简化(script setupref会自动解包,模板中直接用count即可)。

七、扩展思考:4个高频问题解答

问题1:script setup支持所有组合式API吗?

解答:支持!refreactivewatchcomputed等组合式API,以及onMountedonUpdated等生命周期钩子,都可以在script setup顶层直接使用。

问题2:script setup能访问组件实例this吗?

解答:不能!script setup是基于组合式API的语法糖,设计上避免使用thisthissetup函数中是undefined)。需要访问实例属性时,建议用getCurrentInstance(但不推荐,会增加耦合):

<script setup>
import { getCurrentInstance } from 'vue';
const instance = getCurrentInstance(); // 获取当前组件实例
console.log(instance?.proxy?.$route); // 访问路由(需谨慎使用)
</script>

问题3:script setup如何处理作用域样式?

解答scoped样式在script setup中正常工作,样式仅影响当前组件的模板。如果需要穿透样式(如修改子组件样式),可以用::v-deep(Vue3推荐用:deep()):

<style scoped>
:deep(.child-component-class) {
  color: red;
}
</style>

问题4:script setup的性能比普通<script>好吗?

解答:性能无差异!script setup是编译时的语法糖,最终会被编译为普通的setup函数,运行时行为完全一致。

结尾:用script setup,写更爽的Vue组件

script setup不是颠覆,而是进化——它用更少的代码,让Vue组件的逻辑更清晰、开发更高效。无论是新手还是资深开发者,都能快速上手,告别"样板代码"的烦恼~

下次写Vue组件时,不妨试试script setup,你会爱上这种"代码减负"的感觉!如果这篇文章帮你理清了思路,记得点个收藏,咱们下期,不见不散!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端布洛芬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值