Appearance
使用 setup() 函数的效果:

html
<template>
<button @click="change">+1</button>
<div>{{ text }}</div>
{{ flag }}
</template>
<script lang="ts">
import { ref,defineComponent } from 'vue'
export default defineComponent({
setup() {
const flag = ref(false)
let text = 111
const change = () => {
text ++
flag.value = !flag.value
}
return {
flag,
text,
change
}
}
})
</script>使用 <script setup> 时的效果:

html
<template>
<button @click="change">+1</button>
<div>{{ text }}</div>
{{ flag }}
</template>
<script setup lang="ts">
import { ref } from 'vue'
const flag = ref(false)
let text = 111
const change = () => {
text ++
flag.value = !flag.value
}
</script>两段代码看上去几乎一模一样,但在运行时却会发现,使用 setup() 函数的版本中页面中 text 的值不会变化,而 <script setup> 版本中页面中 text 的值会变化。为了理解这种现象,我决定查看编译后的产物。
setup()产物
js
export default {
setup() {
const flag = ref(false);
let text = 111;
const change = () => {
text++;
flag.value = !flag.value;
};
return {
flag,
text, // 这里是值传递
change
};
}
}在 setup() 函数中,返回的 text 是一个普通的局部变量。通过值传递的方式在返回对象中暴露出来。因此,当 text 的值变化时,由于它不是响应式的,Vue 无法追踪到这种变化,也就不会触发视图的更新。
<script setup>产物
js
const __sfc__ = /*#__PURE__*/defineComponent({
setup(__props, { expose }) {
expose();
const flag = ref(false);
let text = 111;
const change = () => {
text++;
flag.value = !flag.value;
};
return { flag, get text() { return text }, set text(v) { text = v }, change };
}
})在 <script setup> 中,编译器会为顶层变量自动生成 getter 和 setter,即使这些变量本身不是响应式的。这样一来,每次渲染时模板会通过 getter 获取最新值,因此表现出类似响应式的效果。