Vue3.0—setup

Vue3.0的setup函数详解
Vue3.0引入的setup函数是CompositionAPI的核心,它在beforeCreate之前执行,this为undefined。在这个函数中,可以处理数据、方法等,返回的对象可以在模板中直接使用。同时,setup接受props和context参数,提供对props、attrs、slots和emit的访问。不应与Vue2.x的配置混用,且setup不能是async函数,但能返回渲染函数来自定义渲染内容。

拉开序幕的setup

1. 理解:Vue3.0中一个新的配置项,值为一个函数。

2. setup是所有Composition API(组合API)“ 表演的舞台 ”

4. 组件中所用到的:数据、方法等等,均要配置在setup中。

5. setup函数的两种返回值:

1. 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)

2.若返回一个渲染函数:则可以自定义渲染内容。(了解)

6. 注意点:

1. 尽量不要与Vue2.x配置混用

- Vue2.x配置(data、methos、computed...)中可以访问到setup中的属性、方法。

- 但在setup中不能访问到Vue2.x配置(data、methos、computed...)。

- 如果有重名, setup优先。

2. setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

setup的两个注意点

- setup执行的时机

-在beforeCreate之前执行一次,this是undefined。

- setup的参数

- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。

- context:上下文对象

- attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于```this.$attrs```。

- slots:收到的插槽内容, 相当于 ```this.$slots```。

- emit: 分发自定义事件的函数, 相当于 ```this.$emit```。

<template>
    <h1>一个人的信息</h1>
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <button @click="test">测试触发一下Demo组件的Hello事件</button>
</template>
<script>
    import {reactive} from 'vue'
    export default {
        name: 'Demo',
        props:['msg','school'],
        emits:['hello'],
        setup(props,context){
            // console.log('---setup---',props)
            // console.log('---setup---',context)
            // console.log('---setup---',context.attrs) //相当与Vue2中的$attrs
            // console.log('---setup---',context.emit) //触发自定义事件的。
            console.log('---setup---',context.slots) //插槽
            //数据
            let person = reactive({
                name:'张三',
                age:18
            })
            //方法
            function test(){
                context.emit('hello',666)
            }
            //返回一个对象(常用)
            return {
                person,
                test
            }
        }
    }
</script>

<think>我们正在使用Vue 3的Composition API,特别是setup函数,来实现子组件向父组件传值。 根据引用[3]和引用[4],我们知道在setup函数中,我们可以使用第二个参数(通常命名为context)来访问emit方法。 步骤: 1. 在子组件中,我们通过setup的第二个参数(context)获取emit函数。 2. 定义一个函数(例如sendDataToParent),在这个函数中调用emit方法。 emit方法接受两个参数: - 第一个参数是事件名(字符串),父组件将监听这个事件。 - 第二个参数是要传递的值(可以是任意类型)。 3. 在子组件的模板中,绑定一个事件(比如点击事件)来触发这个函数。 4. 在父组件中,引入子组件并在模板中使用。在子组件标签上使用v-on(或@)来监听子组件发出的事件,并指定一个处理函数。 5. 在父组件的处理函数中,接收传递过来的值。 注意:在Vue 3中,我们使用defineComponent来定义组件。 下面我们分别给出子组件和父组件的代码示例。 子组件(ChildComponent.vue): ```vue <template> <button @click="sendDataToParent">向父组件传值</button> </template> <script> import { defineComponent } from &#39;vue&#39;; export default defineComponent({ name: &#39;ChildComponent&#39;, setup(props, { emit }) { const sendDataToParent = () => { // 通过emit发送一个事件,事件名为&#39;childToParent&#39;,并传递一个数据(这里是一个字符串) emit(&#39;childToParent&#39;, &#39;这是来自子组件的数据&#39;); }; return { sendDataToParent }; } }); </script> ``` 父组件(ParentComponent.vue): ```vue <template> <div> <child-component @child-to-parent="handleChildData" /> <p>父组件接收到的数据: {{ receivedData }}</p> </div> </template> <script> import { defineComponent, ref } from &#39;vue&#39;; import ChildComponent from &#39;./ChildComponent.vue&#39;; export default defineComponent({ name: &#39;ParentComponent&#39;, components: { ChildComponent }, setup() { const receivedData = ref(&#39;&#39;); const handleChildData = (data) => { receivedData.value = data; }; return { receivedData, handleChildData }; } }); </script> ``` 说明: 1. 在子组件中,我们通过setup的第二个参数解构出emit。然后定义了一个sendDataToParent函数,在这个函数中调用emit,事件名为&#39;childToParent&#39;(注意事件名推荐使用kebab-case,因为在父组件中监听时我们使用kebab-case形式)。 2. 在父组件中,我们引入了子组件,并在模板中使用。通过@child-to-parent(即v-on:child-to-parent)监听子组件发出的事件,并绑定到handleChildData方法上。 3. handleChildData方法接收一个参数data,这就是子组件传递过来的数据,我们将其赋值给ref创建的响应式变量receivedData,然后在模板中显示。 注意:在Vue 3中,事件名的大小写不会自动转换,因此我们在子组件emit时使用的事件名是&#39;childToParent&#39;,在父组件中监听时需要使用同样的字符串(但Vue推荐在模板中使用kebab-case,所以这里我们监听的是&#39;child-to-parent&#39;,因为Vue会自动将模板中的事件名转换为小写,而emit时的事件名是大小写敏感的。为了避免问题,通常我们建议在emit和监听时都使用kebab-case命名方式,即emit(&#39;child-to-parent&#39;, ...) 和 @child-to-parent)。 但是,在JavaScript中,事件名是大小写敏感的。在模板中,我们使用v-on(或@)时,事件名会被自动转换为小写(因为HTML是大小写不敏感的)。所以,如果我们在子组件emit时使用驼峰命名(childToParent),在父组件模板中监听时,我们需要写成@child-to-parent(因为HTML特性会转换为小写,所以实际上监听的是小写事件名)。但这样会导致事件名不一致(emit的是驼峰,而监听的是短横线分隔),因此最佳实践是统一使用kebab-case。 因此,我们修改子组件中的emit事件名为&#39;child-to-parent&#39;: 子组件修改: ```javascript emit(&#39;child-to-parent&#39;, &#39;这是来自子组件的数据&#39;); ``` 父组件模板保持不变: ```html <child-component @child-to-parent="handleChildData" /> ``` 这样,事件名就统一了。 总结: - 子组件通过setup的context.emit触发事件(事件名使用kebab-case)。 - 父组件在子组件标签上使用v-on(或@)加上事件名(kebab-case)来监听,并指定处理函数。 这样,我们就实现了在Vue 3中使用setup进行子组件向父组件传值。 注意:在Vue 3.2及以上版本中,我们还可以使用<script setup>语法糖,这样写起来更简洁。但本问题要求使用setup函数,所以我们没有使用语法糖。 如果使用<script setup>,则写法如下: 子组件(ChildComponent.vue): ```vue <template> <button @click="sendDataToParent">向父组件传值</button> </template> <script setup> // 使用defineEmits来声明事件 const emit = defineEmits([&#39;child-to-parent&#39;]); const sendDataToParent = () => { emit(&#39;child-to-parent&#39;, &#39;这是来自子组件的数据&#39;); }; </script> ``` 父组件写法不变。 但请注意,原问题要求使用setup函数,所以我们提供了setup函数的写法。 最后,根据引用[4],我们也可以传递数字或对象,例如: ```javascript emit(&#39;child-to-parent&#39;, 888); emit(&#39;child-to-parent&#39;, { keyName: &#39;I am value&#39; }); ``` 在父组件的处理函数中,就可以接收到这些值。 希望这个回答能帮助你。</think>在 Vue 3.0 中使用 `setup` 函数实现子组件向父组件传值,主要通过 `emit` 方法实现。以下是详细步骤和代码示例: ### 实现步骤 1. **子组件**: - 使用 `setup(props, { emit })` 解构出 `emit` 函数 - 定义方法触发 `emit(&#39;自定义事件名&#39;, 传递数据)` 2. **父组件**: - 在模板中使用 `@自定义事件名="处理函数"` 监听子组件事件 - 在处理函数中接收子组件传递的数据 ### 代码示例 #### 子组件 (ChildComponent.vue) ```vue <template> <button @click="sendToParent">向父组件传值</button> </template> <script> import { defineComponent } from &#39;vue&#39;; export default defineComponent({ setup(props, { emit }) { const sendToParent = () => { // 触发自定义事件,传递数据(可以是任意类型) emit(&#39;childEvent&#39;, { message: &#39;Hello from child!&#39;, value: 123 }); }; return { sendToParent }; } }); </script> ``` #### 父组件 (ParentComponent.vue) ```vue <template> <ChildComponent @child-event="handleChildData" /> <p>接收到的数据:{{ receivedData }}</p> </template> <script> import { defineComponent, ref } from &#39;vue&#39;; import ChildComponent from &#39;./ChildComponent.vue&#39;; export default defineComponent({ components: { ChildComponent }, setup() { const receivedData = ref(null); const handleChildData = (data) => { // 接收子组件传递的数据 receivedData.value = data; console.log(&#39;收到子组件数据:&#39;, data); }; return { receivedData, handleChildData }; } }); </script> ``` ### 关键说明 1. **事件命名规范**: - 推荐使用 `kebab-case` 事件名(如 `child-event`) - 避免使用驼峰命名(HTML 属性大小写不敏感)[^3] 2. **`emit` 的使用**: - 在 `setup` 中通过上下文参数获取 `emit` 函数 - 第一个参数是自定义事件名,第二个是传递的数据[^4] 3. **响应式数据**: - 父组件使用 `ref` 接收数据时需通过 `.value` 访问[^3] ### 注意事项 1. 如果子组件需要修改接收的 props 数据,应使用 `computed` 或本地副本 2. 复杂数据类型传递时建议使用深拷贝避免引用问题[^2] 3.Vue 3.2+ 可使用 `<script setup>` 语法糖简化代码: ```vue <script setup> import { defineEmits } from &#39;vue&#39; const emit = defineEmits([&#39;childEvent&#39;]) const send = () => emit(&#39;childEvent&#39;, data) </script> ``` ### 常见问题解决 - **数据修改后视图不更新**:确保使用响应式 API (`ref`, `reactive`)[^2] - **父组件值意外改变**:传递对象时避免直接修改 props,应创建副本[^2] - **事件监听失败**:检查事件名是否一致(大小写敏感)[^3] > 示例代码演示了基础传值流程,实际使用时可根据需求传递任意数据类型(字符串、数字、对象等)[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值