有兴趣阅读我们的下一本书吗?了解更多关于 使用 React 构建大型 JavaScript Web 应用程序

设计模式

<script setup>

在我们深入研究 `<script setup>` 语法及其含义之前,让我们快速回顾一下两个概念——**单文件组件**和**组合式 API**。

在 Vue 中,SFC 通过使我们能够在一个单独的 **`.vue`** 文件中定义组件的 HTML/CSS 和 JS 来帮助耦合逻辑。单文件组件由三个部分组成

<template>
  <!-- HTML template goes here -->
</template>

<script>
  // JavaScript logic goes here
</script>

<style>
  /* CSS styles go here */
</style>

<template> 包含组件的纯 HTML 标记,<script> 导出包含该组件中所有 JS 逻辑的组件对象构造函数,以及 <style> 包含所有组件样式。

组合式 API 提供了代表 Vue 核心功能的独立函数。这些函数主要用在一个单独的 `setup()` 选项中,该选项充当使用组合式 API 的入口点。

<!-- Template -->

<script>
  export default {
    name: "MyComponent",
    setup() {
      // the setup function
    },
  };
</script>

<!-- Styles -->

请务必阅读 组合式 API 指南,以深入了解组合式 API 相对于传统选项式 API 语法的优势。

<script setup>

<script setup> 是编译时语法糖,允许在使用组合式 API 定义 Vue 选项时使用更简洁高效的语法。根据 Vue 文档,如果 同时使用 SFC 和组合式 API,则推荐使用这种语法。

通过使用 `<script setup>` 块,我们可以将组件逻辑压缩到一个单独的块中,从而无需显式定义 `setup()` 函数。要使用 `<script setup>` 语法,我们只需要在 `<script />` 块中引入 `setup` 属性。

<script setup>
  // ...
</script>

让我们探索 `<script setup>` 提供的一些主要语法差异。

无返回语句

使用 `<script setup>` 语法,我们不再需要在块的末尾定义 `return` 语句。在顶层声明的绑定(函数、变量、导入等)可以直接访问和使用在模板中。

之前

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Username: {{ state.username }}</p>
    <button @click="increment">Increment Count</button>
  </div>
</template>

<script>
  import { ref, reactive, onMounted } from "vue";

  setup() {
    const count = ref(0);
    const state = reactive({username: "John"});

    const increment = () => {
      count.value++;
    };

    onMounted(() => {
      console.log("Component mounted");
    });

    return {
      count,
      state,
      increment
    };
  },
</script>

之后

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Username: {{ state.username }}</p>
    <button @click="increment">Increment Count</button>
  </div>
</template>

<script setup>
  import { ref, reactive, onMounted } from "vue";

  const count = ref(0);
  const state = reactive({ username: "John" });

  const increment = () => {
    count.value++;
  };

  onMounted(() => {
    console.log("Component mounted");
  });
</script>

无本地注册组件

组件导入会在 `<script setup>` 块中自动识别和解析,无需在 `components` 选项中显式声明组件。

之前

<template>
  <ButtonComponent />
</template>

<script>
  import ButtonComponent from "./components/ButtonComponent.vue";

  export default {
    setup() {
      // the setup function
    },
    components: {
      ButtonComponent,
    },
  };
</script>

之后

<template>
  <ButtonComponent />
</template>

<script setup>
  import { ButtonComponent } from "./components/Button";
</script>

defineProps()

通过使用 `defineProps()` 函数,可以在 `<script setup>` 块中直接访问 props。

之前

<template>
  <button>{{ buttonText }}</button>
</template>

<script>
  export default {
    props: {
      buttonText: String,
    },
  };
</script>

之后

<template>
  <button>{{ buttonText }}</button>
</template>

<script setup>
  const { buttonText } = defineProps({
    buttonText: String,
  });
</script>

defineProps() 还允许我们使用纯 TypeScript 声明 props 的形状。

<template>
  <button>{{ buttonText }}</button>
</template>

<script setup lang="ts">
  const { buttonText } = defineProps<{ buttonText: string }>();
</script>

为了在上述类型声明中提供默认的 prop 值,可以使用 `withDefaults()` 编译宏来实现。

<template>
  <button>{{ buttonText }}</button>
</template>

<script setup lang="ts">
  const { buttonText } = withDefaults(defineProps<{ buttonText: string }>(), {
    buttonText: "Initial button text",
  });
</script>

defineProps 仅在 `<script setup>` 中可用,无需导入即可使用。

defineEmits()

与 props 类似,自定义事件可以通过在组件中使用 `defineEmits()` 函数直接在 `<script setup>` 块中发出。

之前

<template>
  <button @click="closeButton">Button Text</button>
</template>

<script>
  export default {
    emits: ["close"],
    setup(props, { emit }) {
      const closeButton = () => emit("close");

      return {
        closeButton,
      };
    },
  };
</script>

之后

<template>
  <button @click="closeButton">Button Text</button>
</template>

<script setup>
  const emit = defineEmits(["close"]);
  const closeButton = () => emit("close");
</script>

与 `defineProps` 一样,`defineEmits` 是一个特殊的关键字,仅在 `<script setup>` 中可用,并且无需导入即可使用。它还允许我们在 TypeScript 环境中直接传递类型。

<template>
  <button @click="closeButton">Button Text</button>
</template>

<script setup lang="ts">
  const emit = defineEmits<{ (e: "close"): void }>(["close"]);
  const closeButton = () => emit("close");
</script>

<script setup>setup()

对于具有大量返回选项和许多本地注册子组件的大型组件,`<script setup>` 语法有助于消除大量样板代码,从而导致更简洁、更专注的组件定义,这反过来有助于使代码库更易读、更易维护。

Flow chart

除了减少样板代码之外,`<script setup>` 语法还提供更好的运行时性能、更好的 IDE 类型推断性能以及使用 TypeScript 声明 props 和发射事件形状的能力。

有关使用 `<script setup>` 语法时需要注意的所有更改的完整列表,请参阅下面共享的官方 Vue 文档。

有用资源