什么是script setup语法糖

<script setup> 是 Vue 3 中新增的语法糖,旨在简化组件中的逻辑代码。使用<script setup> 标签,可以在组件中通过 defineProps、defineEmits 和 defineExpose 等函数声明组件的属性、事件和暴露出去的 API,然后直接在组件模板中使用它们,而无需在 setup() 函数中再次声明。

此外,<script setup> 还支持通过 ref 和 reactive 等函数声明响应式数据,同时在 <template> 中直接使用。

使用<script setup>可以简化代码,并且能够提高开发效率,降低出错率,是 Vue 3 中非常值得推荐的特性。

用通俗易懂的话来说就是:

它简化了在单文件组件中编写组件选项的方式。在 <script setup> 中,可以使用类似于 setup() 函数的方式来定义组件的 props、响应式数据、计算属性、方法、事件等选项。

相比于传统的 <script lang="ts">setup(){}<script><script setup> 的优点有:

  1. 更少的模板代码:使用 <script setup>,可以在同一个区块中定义组件的选项,减少了冗余的代码,提高了代码的可读性和维护性。
  2. 自动推导变量类型:<script setup> 中定义的变量类型可以被自动推导,减少了代码的冗余性和可读性。
  3. 更好的性能:Vue 3 中,<script setup> 中定义的变量会被自动标记为只读的,这意味着 Vue 可以更好地优化渲染性能。

总之,<script setup> 使得编写组件选项变得更加简洁、易读、易维护,并且能够提高渲染性能。

案例见真知

使用<script setup>语法糖编写组件的代码更为简洁和易读,相比之下,不使用语法糖则需要更多的代码来完成相同的功能。

下面是一个使用<script setup>的组件示例,它是一个简单的计数器:

<template>
  <div>
    <p>当前计数为:{{ count }}</p>
    <button @click="incrementCount">增加计数</button>
  </div>
</template>

<script setup>
  import { ref } from 'vue'

  const count = ref(0)

  function incrementCount() {
    count.value++
  }
</script>

相比之下,下面是不使用语法糖的同一个组件的代码:

phpCopy code<template>
  <div>
    <p>当前计数为:{{ count }}</p>
    <button @click="incrementCount">增加计数</button>
  </div>
</template>

<script>
  import { ref } from 'vue'

  export default {
    setup() {
      const count = ref(0)

      function incrementCount() {
        count.value++
      }

      return {
        count,
        incrementCount,
      }
    },
  }
</script>

可以看到,使用<script setup>语法糖可以更清晰地表达组件的代码逻辑,同时也能更快地编写代码。

注意事项

你还记得前面提到的语法糖的定义吗?

Tip

使用<script setup> 标签,可以在组件中通过 defineProps、defineEmits 和 defineExpose 等函数声明组件的属性、事件和暴露出去的 API,然后直接在组件模板中使用它们,而无需在 setup() 函数中再次声明。

如果记得,那么一定请记住无需显示export default导出 画蛇添足,因为不需要也不允许明令禁止!

举个例子,在<script setup>语法糖中将属性暴露出去给父组件传递属性props,我们只需要如下这样做

<template>
  <footer>
    <div class="center">
      <span>Copyright&nbsp;©{{ startYear }}-{{ currentYear }}&nbsp;{{ author }}&nbsp;</span>
      <span v-if="icpNumber" class="icp-number">
        <a href="http://beian.miit.gov.cn" target="_blank">{{ icpNumber }}</a>
      </span>
    </div>
  </footer>
</template>
<script lang="ts" setup>
import { defineProps } from "vue";

interface PageFooterProps {
  startYear: number;
  author: string;
  icpNumber?: string;
}

const props = defineProps<PageFooterProps>();

const currentYear = new Date().getFullYear();
</script>
<style lang="less" scoped>
footer {
  //   height: 10%;
  background-color: #f3f4f5;
  display: flex;
  justify-content: center;
  align-items: center;

  .center {
    text-align: center;
    color: #4e77ab;
    a {
      text-decoration: none;
      color: #4979ff;
    }
  }
}
</style>

也就是const props = defineProps<PageFooterProps>();,不需要再在前面加上exportdefault了,这不合法、也不允许!

Warning

1、由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法
2、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了undefined
3、setup函数只能是同步的不能是异步的

<script setup>语法糖小结

作用

  • 简化组合式 API 的使用体验
  • 自动暴露 setup() 返回的值给模板使用

规则

  • 不能使用 export
  • 可以使用 import 导入
  • 可以配合 Typescript 使用

用法

<script setup> 
// 这里可以直接使用组合式 API,不需要绑定到 setup()
import { ref } from 'vue'
let message = ref('Hello!')
</script>

<template>
  {{ message }} 
</template>

暴露方法

  • 普通声明:使当前模板可以访问
  • defineExpose():暴露给其他组件
  • defineEmit():定义自定义事件

defineExpose()

  • 用于在 <script setup> 中暴露变量和方法给其他组件使用
  • 格式:defineExpose({ 暴露的变量或方法 })
<!-- ComponentA.vue -->
<script setup>
import { defineExpose } from 'vue'

const add = (a, b) => a + b 

defineExpose({ add })
</script> 

<!-- ComponentB.vue -->
import ComponentA from './ComponentA.vue'

const { add } = ComponentA 

add(1, 2) // 3
</script>

defineEmit()

用于在 <script setup> 中定义自定义事件

  • 格式:const emit = defineEmit(['eventName'])
  • 可以使用 emit('eventName') 触发事件
    ComponentA.vue:
<!-- ComponentA.vue -->
<script setup>
import { defineEmit } from 'vue'

const emit = defineEmit(['add'])

function onAdd() {
  emit('add') 
}
</script>

ComponentB.vue:

<!-- ComponentB.vue -->  
<script setup>
import ComponentA from './ComponentA.vue' 

const instance = ComponentA()

instance.$on('add', () => {
  console.log('add event fired')
})
</script>