💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[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)