[TOC]
# 1. setup执行时机问题
* `setup`函数在`beforeCreate`生命周期函数之前执行一次且也只执行一次,此时组件对象还没有创建。
* `this`此时是`undefined`,所以不能在`setup`内通过`this`来访问`data/computed/methods/props`。
* 其实所有的composition API相关回调函数中也都不可以通过`this`来访问。
```html
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
console.log("setup方法执行了!");
//this此时是undefined
console.log(this);
return {};
},
beforeCreate() {
console.log("beforeCreate方法执行了!");
},
});
</script>
```
打印顺序如下,可见`setup`是在`beforeCreate`之前执行的。
```
setup方法执行了!
undefined
beforeCreate方法执行了!
```
<br/>
# 2. setup的返回值
* `setup`函数一般都返回一个对象,为模板提供数据,也就是模板中可以直接使用此对象中的所有属性/方法。
* `setup`函数返回对象中的属性会与`data`函数返回对象的属性合并成为组件对象的属性。
* `setup`函数返回对象中的方法会与`methods`中的方法合并成为组件对象的方法。
* 如果`data`与`methods`有重名,`setup`优先。
* 注意:
* 一般不要将`data`与`setup`混合使用,`methods`与`setup`混合使用。
* `methods`中可以访问`setup`提供的属性和方法,但在`setup`方法中不能访问`data`和`methods`,因为在`setup`中此时组件还没创建好,`this`是`undefined`。
* `setup`不能是一个`async`函数,因为添加了`async`,则`setup`返回值不再是一个简单对象,而是 Promise 对象,在模板中是看不到 Promise 对象中的属性数据的。
```html
<template>
<div>
<!-- msg01与msg02都可以在模板中访问到 -->
<h3>msg01: {{ msg01 }}</h3>
<h3>msg02: {{ msg02 }}</h3>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
//不能声明为 async setup() {..}
setup() {
const msg01 = "setup中的msg01属性";
const getMsg01 = () => {
console.log("setup的getMsg01函数");
};
return {
msg01,
getMsg01,
};
},
data() {
const msg02 = "data中的msg02属性";
return {
msg02,
};
},
methods: {
getMsg02: () => {
console.log("methods中的getMsg02函数");
},
},
mounted() {
console.log(this);
},
});
</script>
```
`mounted`输出内容如下,可以`this`其实也是一个代理对象。在`setup`、`data`、`methods`中声明的属性与函数都合并为了组件的属性与函数。
![](https://img.kancloud.cn/16/f4/16f46ca8a519595fa7ad4707f66203b7_1530x149.jpg)
<br/>
# 3. setup的参数
* `setup(props, context)` / `setup(props, {attrs, slots, emit})`
* props: 是一个对象,该对象包含了父组件向子组件传递的所有数据,并且是在子组件的`props`中接收到的所有属性。
* context:是一个对象,包含`attrs、slots、emit`三个属性,所以一般也写成`setup(props, {attrs, slots, emit})`。
* attrs: 包含没有在props配置中声明的属性的对象,相当于 this.$attrs
* slots: 包含所有传入的插槽内容的对象,相当于 this.$slots
* emit: 用来分发自定义事件的函数,相当于 this.$emit
**1. 父组件:SetupParamsParent.vue**
```html
<template>
<h3>父组件</h3>
<h4>msg: {{ msg }}</h4>
<hr />
<!-- 在父组件中给子组件传递属性和添加事件 -->
<SetupParamsChild
:message="msg"
:message2="msg"
@updateMessage="updateMessage"
></SetupParamsChild>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import SetupParamsChild from "./SetupParamsChild.vue";
export default defineComponent({
setup() {
const msg = ref("父组件传递的参数!");
const updateMessage = (newMsg: string) => {
msg.value += newMsg;
};
return {
msg,
updateMessage,
};
},
components: {
SetupParamsChild,
},
});
</script>
```
**2. 子组件:SetupParamsChild.vue**
```html
<template>
<h3>子组件</h3>
<!-- 3. 模板中不可以直接调用message2属性,但是可以直接调用message属性 -->
<h3>messsage: {{ message }}</h3>
<!-- 4. 子组件中触发父组件的事件 -->
<button @click="updateMessage">updateMessage</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup(props, context) {
//1. message在props中已经声明,message2没有
console.log(props.message);
//父组件传递的参数!
console.log(context.attrs.message2);
//父组件传递的参数!
const updateMessage = () => {
//2. 分发事件
context.emit("updateMessage", "++");
};
return {
updateMessage,
};
},
props: ["message"],
});
</script>
```
**3. 效果如下**
![](https://img.kancloud.cn/54/36/5436d2b28eb2f39af94dca087c1ba64c_1250x308.gif)
- nodejs
- 同时安装多个node版本
- Vue3
- 创建Vue3项目
- 使用 vue-cli 创建
- 使用 vite 创建
- 常用的Composition API
- setup
- ref
- reactive
- 响应数据原理
- setup细节
- reactive与ref细节
- 计算属性与监视
- 生命周期函数
- toRefs
- 其它的Composition API
- shallowReactive与shallowRef
- readonly与shallowReadonly
- toRaw与markRaw
- toRef
- customRef
- provide与inject
- 响应式数据的判断
- 组件
- Fragment片断
- Teleport瞬移
- Suspense
- ES6
- Promise对象
- Promise作用
- 状态与过程
- 基本使用
- 常用API
- async与await
- Axios