Vue3.0组合式API:setup()函数

1、什么是组合式API

Vue 3.0 中新增了组合式 API 的功能,它是一组附加的、基于函数的 API,可以更加灵活地组织组件代码。通过组合式 API 可以使用函数而不是声明选项的方式来编写 Vue 组件。因此,使用组合式 API 可以将组件代码编写为多个函数,每个函数处理一个特定的功能,不再需要按选项组织代码。

组合式 API 可以更好地和 TypeScript 集成,同时,组合式 API 可以和现有的基于选项的 API 一起使用。需要注意的是,组合式 API 是在选项(data、methods 和 computed)之前进行解析,因此组合式 API 无法访问这些选项中定义的属性。

2、setup()函数的基本用法

setup() 函数是一个新的组件选项,它是组件内部使用组合式 API 的入口。setup() 函数在组件实例创建之前,初始化 Prop 之后调用,而且 setup() 函数是在 beforeCreate 钩子函数之前调用。

setup() 函数可以返回一个对象或函数,对象的属性会合并到组件模板渲染的上下文中。

**【实例】**创建一个组件,使用 setup() 函数实现一个计数器功能。

html 复制代码
<template>
    <div>
        <h3>{{ blogInfo.name }}</h3>
        <h3>{{ blogInfo.url }}</h3>
        <p>计数结果:{{ count }}</p>
        <button @click="counter">计数器</button>
    </div>
</template>

<script>
import { ref, reactive, onMounted, onUnmounted } from 'vue';

export default {
    setup() {

        // 使用 ref 创建响应式的基本类型
        const count = ref(0);

        // 使用 reactive 创建响应式的复杂类型
        const blogInfo = reactive({
            name: '您好,欢迎访问 pan_junbiao的博客',
            url: 'https://blog.csdn.net/pan_junbiao'
        });

        // 挂载时的操作
        onMounted(() => {
            console.log('组件已挂载');
        });

        // 卸载时的操作
        onUnmounted(() => {
            console.log('组件已卸载');
        });

        // 增加计数的方法
        function counter() {
            count.value++;
        }

        // 返回需要在模板中使用的数据和方法
        return {
            blogInfo,
            count,
            counter
        };
    }
};
</script>

执行结果:

上述代码中,setup() 函数返回的是一个对象,在对象有三个属性,其中两个响应式对象,和一个函数。在组件的模板仲可以直接使用这些属性。

注意:

setup() 函数中不能使用 this。但是,当和现有的基于选项的 API 一起使用时,在选项中可以通过 this 访问 setup() 函数返回的实现。

3、setup()函数的参数

setup() 函数可以接收两个可选的参数。第一个参数是响应式的 props 对象,第二个参数是一个上下文(context)对象。

3.1 第一个参数:响应式的 props 对象

第一个参数是响应式的 props 对象,通过该参数可以访问 props 选项中定义的 Prop。

**【实例】**使用setup()函数中的第一个参数:响应式的 props 对象。

(1)创建 ParentComponent.vue 父组件

html 复制代码
<template>
    <fieldset>
        <legend>父组件</legend>
        <h3>使用Prop实现父组件向子组件传递数据</h3>
        <!-- 第三步:使用组件,并向子组件传递数据 -->
        <ChildComponent :blogName="blogInfo.blogName" :blogUrl="blogInfo.blogUrl" />
    </fieldset>
</template>

<script>
import { reactive } from 'vue';

//第一步:引用组件
import ChildComponent from '@/components/ChildComponent.vue'

export default {
    //第二步:注册组件
    components: {
        ChildComponent,
    },
    setup() {
        // 使用 reactive 创建响应式的对象
        const blogInfo = reactive({
            blogName: '您好,欢迎访问 pan_junbiao的博客',
            blogUrl: 'https://blog.csdn.net/pan_junbiao'
        });

        //返回
        return {
            blogInfo
        }
    }
}
</script>

(2)创建 ChildComponent.vue 子组件

html 复制代码
<template>
    <fieldset>
        <legend>子组件</legend>
        <p>博客信息:{{ props.blogName }}</p>
        <p>博客地址:{{ props.blogUrl }}</p>
    </fieldset>
</template>

<script>
export default {
    // 使用 props 属性:接收父组件传递过来的数据
    props: ['blogName', 'blogUrl'],

    //setup()函数的第一个参数是响应式的 props 对象。
    setup(props) {
        return {
            props
        };
    }
}
</script>

<style scoped>
fieldset {
    font-size: 18px;
    color: blue;
}
</style>

(3)在 App.vue 根组件中,引入父组件

html 复制代码
<template>
  <!-- 第三步:使用组件 -->
  <ParentComponent />
</template>
 
<script>
//第一步:引用组件
import ParentComponent from '@/components/ParentComponent.vue'
 
export default {
  //第二步:注册组件
  components: {
    ParentComponent,
  }
}
</script>

执行结果:

3.2 第二个参数:上下文(context)对象

第二个参数是一个上下文(context)对象,该对象是一个 JavaScript 对象,它暴露了 attrs、slots 和 emit 三个属性。其中,attrs 和 slots 是有状态的对象,它们会随着组件的更新而发生变化,但是这两个对象本身并不是响应式的,因此不能对它们进行解构。

**【实例】**使用setup()函数中的第二个参数:上下文(context)对象。

javascript 复制代码
export default {
    //setup()函数的第一个参数:响应式的 props 对象。
    //setup()函数的第二个参数:上下文(context)对象
    setup(props, context) {
        //属性(非响应式对象)
        console.log('属性:', context.attrs);

        //插槽(非响应式对象)
        console.log('插槽:', context.slots);

        //发生的事件(方法)
        console.log('事件:', context.emit);
    }
}

4、使用 <script setup> 语法糖

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。在 Vue3.2 中只需要在 script 标签上加上 setup 属性,无需 return,template 便可直接使用。相比于普通的 <script> 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 TypeScript 声明 props 和自定义事件。
  • 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
  • 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。

**【实例】**使用 <script setup> 语法糖,重构上述的计数器功能。

html 复制代码
<template>
    <div>
        <h3>{{ blogInfo.name }}</h3>
        <h3>{{ blogInfo.url }}</h3>
        <p>计数结果:{{ count }}</p>
        <button @click="counter">计数器</button>
    </div>
</template>

<!-- 使用 <script setup> 语法糖 -->
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';

// 使用 ref 创建响应式的基本类型
const count = ref(0);

// 使用 reactive 创建响应式的复杂类型
const blogInfo = reactive({
    name: '您好,欢迎访问 pan_junbiao的博客',
    url: 'https://blog.csdn.net/pan_junbiao'
});

// 挂载时的操作
onMounted(() => {
    console.log('组件已挂载');
});

// 卸载时的操作
onUnmounted(() => {
    console.log('组件已卸载');
});

// 增加计数的方法
function counter() {
    count.value++;
}

</script>

执行结果:

相关推荐
繁依Fanyi29 分钟前
828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件
服务器·开发语言·前端·python·算法·华为·华为云
叫我小鹏呀37 分钟前
vue3中el-table中点击图片放大时,被表格覆盖
前端·javascript·vue.js
我命由我1234544 分钟前
2.使用 VSCode 过程中的英语积累 - Edit 菜单(每一次重点积累 5 个单词)
前端·javascript·ide·vscode·学习·编辑器·学习方法
四季予你661 小时前
vue2 和 vue3 的区别
前端·javascript·vue.js
炒毛豆1 小时前
vue3+ant design vue实现可编辑表格弹出气泡弹出窗~
前端·javascript·vue.js
寰宇软件1 小时前
vue组件注册
前端·javascript·vue.js
林一怂儿1 小时前
H5 three.js 实现六年级观察物体
开发语言·javascript
OEC小胖胖2 小时前
js进阶-作用域是什么
开发语言·前端·javascript·ecmascript·web
东方翱翔2 小时前
HTML中的文字与分区标记
java·前端·html