查看vue3官网介绍:组合式 API:setup()
在 Vue 3 中,组合式 API 的 setup()
函数是一个非常重要的特性,它提供了一种更灵活和可维护的方式来组织组件的逻辑。
基本概念
setup()
函数是在组件实例创建之前执行的,它用于组合组件的逻辑,包括响应式数据、方法、计算属性、监听等。它接收两个参数:props
和 context
,并返回一个对象,其中包含可以在组件模板中使用的属性和方法。
特点
setup
函数返回的对象中的内容,可直接在模板中使用。setup
中访问this
是undefined
。setup
函数会在beforeCreate
之前调用,它是“领先”所有钩子执行的。
示例:
<template><div><div>姓名:{{name}}</div><div>年龄:{{age}}</div><button @click="changeName">修改名字</button><button @click="changeAge">修改年龄</button></div>
</template>
<script lang="ts">
export default {name: 'Person',setup() {console.log(this); // undefined// 数据(在setup中直接声明变量,此时的name、age、tel都不是响应式的数据)// 注意:直接声明变量,数据不是响应式的。let name = '张三'let age = 36// 方法function changeName() {console.log('change name')name = 'John' // 这样修改name,页面是不会响应的console.log('changed name: ' + name); // changed name: John// 成功修改 name ,但是页面没有响应}function changeAge() {age--console.log(age);// 成功修改 age ,但是页面没有响应}// 将数据、方法暴露出去,模板中才可以使用return { name, age, changeName, changeAge}}
}
</script>
setup
函数的返回值
- 若返回一个对象:则对象中的:属性、方法等,在模板中均可以直接使用。
- 若返回一个函数:则可以自定义渲染内容。代码如下:
// 不论页面模板是什么样,直接渲染返回的内容
setup(){return ()=> 'vue3起飞!'
}
与选项式API的区别
setup
与 选项式API可以在vue3项目中同时存在。- 选项式API(如
data
、methods
、computed
等)中可以访问到setup
中的属性、方法。
但在setup中不能访问到选项式API(如data
、methods
、computed
等)。- 在选项式 API 中可以访问到
setup
中定义的属性和方法,这是因为 Vue 在处理组件时,会先执行setup
函数,然后将其返回值与选项式 API 的内容进行合并,最终形成组件的实例。 - 在
setup
函数中不能直接访问选项式 API(如data
、methods
、computed
等),这是因为setup
函数在组件实例创建之前执行,此时选项式 API 的内容还未被处理和合并到组件实例中。
- 在选项式 API 中可以访问到
- 如果与选项式API冲突,则
setup
优先。setup
的执行优先级更高,setup
返回的属性会覆盖选项式 API 中同名的属性。
示例:
<template><div><div>姓名:{{name}}</div><div>年龄:{{age}}</div><button @click="changeName">修改名字</button><button @click="changeAge">修改年龄</button><br /><div>选项式API data 里的数据:{{ otherName }}</div><div>选项式API data 里读取setup函数中声明的变量: {{ setupName }}</div><button @click="handleShow">选项式API methods 定义的方法:点击显示消息</button></div>
</template>
<script lang="ts">
export default {name: 'Person',data() {return {otherName: '李四',setupName: this.name}},methods: {handleShow() {alert('点击了啊啊啊啊啊')}},setup() {console.log(this); // undefined// 数据(在setup中直接声明变量,此时的name、age、tel都不是响应式的数据)// 注意:直接声明变量,数据不是响应式的。let name = '张三'let age = 36// 方法function changeName() {console.log('change name')name = 'John' // 这样修改name,页面是不会响应的console.log('changed name: ' + name); // changed name: John// 成功修改 name ,但是页面没有响应}function changeAge() {age--console.log(age);// 成功修改 age ,但是页面没有响应}// 将数据、方法暴露出去,模板中才可以使用return { name, age, changeName, changeAge}}
}
</script>
与传统的选项式 API(如 data
、methods
、computed
等)相比,组合式 API 更加灵活和可组合。它允许将相关的逻辑封装在函数中,提高了代码的复用性和可读性。同时,组合式 API 也更好地支持 TypeScript,提供了更好的类型推断和代码提示。
setup 语法糖
在 Vue 3 中,<script setup>
是一种语法糖,它极大地简化了组合式 API 的使用方式。
<script setup>
语法糖,可以把setup
独立出去:
在 Vue 组件中,使用<script setup>
标签来代替传统的<script>
标签。
在<script setup>
中,不需要使用传统的export default
语法来包裹组件的逻辑。可以直接定义响应式数据、计算属性、方法等,并且这些定义会自动暴露给模板使用(不需要return
语句来暴露数据、方法)。
把上面例子中的setup
函数改为<script setup>
语法糖:
<script setup lang="ts">
console.log(this) // undefined
// 数据(在setup中直接声明变量,此时的name、age、tel都不是响应式的数据)
// 注意:直接声明变量,数据不是响应式的。
let name = '张三'
let age = 36// 方法
function changeName() {console.log('change name')name = 'John' // 这样修改name,页面是不会响应的console.log('changed name: ' + name) // changed name: John// 成功修改 name ,但是页面没有响应
}
function changeAge() {age--console.log(age)// 成功修改 age ,但是页面没有响应
}
</script>
注意:用<script setup>
改写setup
函数后,现在有两个 <script>
标签:
- 一个用于使用组合式 API 的
<script setup>
。 - 一个用于传统的选项式 API 和组件配置:
<script lang="ts">
export default {name: 'Person'
}
</script>
这个<script>
标签目前只用来配置组件的名称。
是否可以在<script setup>
标签上写组件的名称呢?
插件vite-plugin-vue-setup-extend
vite-plugin-vue-setup-extend
是一个用于增强 Vue 3 在 Vite 项目中使用<script setup>
语法的插件。
在 插件vite-plugin-vue-setup-extend 中,有更详细的用法示例。
安装插件:
npm i vite-plugin-vue-setup-extend -D
在vite.config.js
文件中,引入并使用该插件:
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),VueSetupExtend(),]
})
修改<script setup>
标签:
<script setup lang="ts" name="Person">
<script>
参数介绍
setup()
函数接收两个参数:props
和 context
:
props
:包含了父组件传递给当前组件的属性。可以通过解构赋值的方式获取特定的属性。context
:包含了一些与组件相关的上下文信息,如attrs
、slots
、emit
等。可以通过解构赋值的方式获取特定的上下文信息。
示例:
<script setup lang="ts">
// defineProps 用于定义组件接收的父组件传递过来的属性(props)。
// defineExpose 用于明确指定哪些属性和方法可以在组件外部被访问。
import { defineProps, defineExpose } from 'vue';// 定义props
// 通过 defineProps 返回的对象可以访问到父组件传递过来的这个属性的值。
const props = defineProps({message: String
});console.log(props.message);// defineEmits 用于定义组件可以触发的自定义事件。
// 这里定义了一个名为 customEvent 的自定义事件。
const emit = defineEmits(['customEvent']);// customMethod 是一个方法,当这个方法被调用时,
// 会触发 customEvent 事件,并传递 'some data' 作为事件参数。
const customMethod = () => {emit('customEvent', 'some data');
};// 通过 defineExpose 指定了组件外部可以访问的内容。
// 这里只暴露了 customMethod 方法,在父组件或者其他组件中可以调用这个方法,
// 但不能直接访问组件内部的其他未暴露的属性和方法。
defineExpose({customMethod
});
</script>
返回值
- 响应式数据:可以在
setup()
函数中使用ref
或reactive
函数来创建响应式数据。这些数据可以在组件模板中使用,并且会自动更新视图。
示例:
<template><div><p>Count: {{ count }}</p><button @click="increment">Increment</button></div>
</template>
<script setup lang="ts">import { ref } from 'vue';const count = ref(0);const increment = () => {count.value++;};</script>
- 计算属性:可以在
setup()
函数中使用computed
函数来创建计算属性。计算属性是基于响应式数据计算得到的值,并且会自动更新。
示例:
<template><div><p>Full Name: {{ fullName }}</p></div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';const firstName = ref('John');
const lastName = ref('Doe');const fullName = computed(() => `${firstName.value} ${lastName.value}`);
</script>
- 方法:可以在
setup()
函数中定义普通的函数,这些函数可以在组件模板中使用。
示例:
<template><div><p>Count: {{ count }}</p><button @click="increment">Increment</button><button @click="decrement">Decrement</button></div>
</template>
<script setup lang="ts">
import { ref } from 'vue';const count = ref(0);const increment = () => {count.value++;
};const decrement = () => {count.value--;
};
</script>