<script setup>
在深入研究 <script setup>
语法及其含义之前,我们先快速回顾一下两个概念—— 单文件 组件和组合式 API。
在 Vue 中,单文件组件允许我们在一个单独的 .vue
文件中定义组件的 HTML CSS 和 JS,从而帮助我们组织程序的逻辑。单文件组件由三个部分组成:
<template>
<!-- HTML 模板写在这 -->
</template>
<script>
// JavaScript 逻辑写在这
</script>
<style>
/* CSS 样式写在这 */
</style>
<template>
包含组件的原始 HTML,<script>
导出了一个包含该组件全部 JS 逻辑的对象的构造函数,<style>
包含组件全部的样式。
组合式 API 提供了一系列代表了 Vue 的核心功能的独立函数,这些函数主要在 setup()
中使用。setup()
是组合式 API 的入口点。
<!-- 模板 略 -->
<script>
export default {
name: "MyComponent",
setup() {
// setup 函数
},
};
</script>
<!-- 样式 略 -->
确保已经阅读过 组合式,以深入了解组合式 API 对于传统的选项式 API 所具有的优势。
<script setup>
<script setup>
是 Vue 的编译时语法糖,允许使用一种简洁高效的方式通过组合式 API 来定义 Vue 实例。根据 Vue 的官方文档,如果同时使用单文件组件和组合式 API,这是最推荐的语法。
通过 <script setup>
,我们可以把我们的组件逻辑压缩到一个单独的代码块中,无需显式调用 setup()
函数。要使用 <script setup>
,我们只需要向 <script>
标签中添加 setup
属性。
<script setup>
// ...
</script>
我们来看一下 <script setup>
语法的主要特点。
无返回值
在 <script setup>
中,我们不需要在 JS 代码的最后提供返回值。在上面声明的值(方法、变量、导入等)都可以在模板中直接使用。
<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>
无需显式引入组件
导入的组件会自动识别和解析,不需要在组件中显式地使用 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()
在 <script setup>
中,可以直接使用 defineProps()
访问 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>
要在纯 TypeScript 定义的 props 中提供默认值,我们需要使用 withDefaules()
宏。
<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 类似,可以使用 <script setup>
中的 defineEmits()
方法定义自定义事件,并可以通过其返回值直接触发事件。
<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>
语法有助于减少大量的样板代码,从而我们可以获得一个更清晰且更集中的组件定义,进而让代码具有更好的可读性,也更易于维护。
<template>
<!-- 模板 -->
</template>
<script>
import { ref, computed, reactive, watch } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
export default {
name: 'MyComponent',
components: {
ComponentA,
ComponentB
},
setup() {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => {
count.value ++
}
const decrement = () => {
count.value --
}
return {
count,
doubleCount,
increment,
decrement
}
}
}
</script>
<template>
<!-- 模板 -->
</template>
<script setup>
import { ref, computed, reactive, watch } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => {
count.value ++
}
const decrement = () => {
count.value --
}
</script>
除了减少样板代码之外,<script setup>
语法还提供了更好的运行时性能、更好的 IDE 类型推导性能,以及使用 TypeScript 声明 props 和自定义事件的能力。
关于使用 <script setup>
都需要哪些更改,请参阅下面的 Vue 官方文档。