返回 导航

Vue.js

hangge.com

Vue.js 3 - Composition API使用详解1(setup函数基本使用)

作者:hangge | 2026-04-24 08:57
    在 Vue.js 2 中,我们使用 Options API 的方式编写组件。Options API 最大的特点就是在对应的属性中编写对应的功能模块,比如在 data 中定义数据,在 methods 中定义方法,在 computed 中定义计算属性,在 watch 中监听属性改变,以及在组件中定义生命周期函数等。但是,使用 Options API 这种方式编写代码会带来一些弊端:
  • 代码逻辑会被拆分,在实现某一功能时,对应的代码逻辑会被拆分到各个属性中。 
  • 当组件变得更大、更复杂时,逻辑关注点的列表就会变长,同一个功能的逻辑会被拆分得非常分散。 
  • 对维护这些复杂组件的开发者来说,过于分散的逻辑代码难以阅读和理解。
    Composition API(组合式 API)是 Vue 3 的核心特性之一。它可以让我们把逻辑按“功能”划分,而不是散落在 datacomputedwatchmethods 等各个选项中,使得代码阅读和复用都变得更加自然。在 Vue.js 3 组件中,如果想要使用 CompositionAPI 这种方式来编写代码,需要在 setup 函数中编写或使用 <script setup> 语法糖。下面我们看看应该如何在 setup 函数中编写 Composition API

一、setup 函数基本使用

1,setup 函数介绍

(1)setup 函数实际上是 Vue.js 3 组件的一个选项。不同于之前的 methodscomputedwatchdata 和生命周期等选项,setup 函数的功能非常强大,可以替代之前的大部分选项。setup 函数会在组件被创建之前、props 被解析之后执行,它是编写 Composition API 的入口。

(2)特别要注意一下 setup 函数中 this 指向的问题。 根据 Vue.js 3 官方文档中的描述,this 并没有指向当前组件实例。此外, 在调用 setup 函数之前,datacomputedmethods 等都没有被解析。Vue.is3 框架也没有为 setup 函数绑定 this,因此无法在 setup 中获取 this

2,setup 函数的参数 1:props

(1)setup 函数主要有两个参数:propscontextprops 作为第一个参数,父组件传递过来的属性会被放到 props 对象中。因此,我们可以直接通过该参数获取父组件传递过来的属性。

(2)首先我们创建一个 SetupProps.vue 组件,代码如下:
  • 首先,在 props 选项中定义字符串类型的 message 属性。
  • 接着,在组件中添加 setup 函数,该函数接收一个 props 参数。
  • 然后,在该函数中分别打印 propsprops.message
注意setup 函数可以直接通过参数来接收 props 对象,不可以通过 this 获取,因为 setup 函数没有绑定 this
<template>
  <div class="setup-props" style="border:1px solid #ddd;margin:10px">
    SetupProps组件
    <h4>{{message}}</h4>
  </div>
</template>

<script>
  export default {
    props: {
      message: {
        type: String,
        required: true
      }
    },
    /**参数一: props, 父组件传递过来属性*/
    setup(props) {
      console.log(props)  
      console.log(props.message)
    }
  }
</script>

(3)接着在在 App.vue 组件中使用 <setup-props> 组件时为其 message 属性传递数据。
<template>
    <div class="app" style="border:1px solid #ddd;margin:4px">
        App组件
        <setup-props message="学习setup函数的参数"></setup-props>
    </div>
</template>

<script>
import SetupProps from './SetupProps.vue';
export default {
    components: {
        SetupProps
    }
}
</script>

(4)运行效果如下下图所示。可以看到,在 SetupProps.vue 组件中定义的 message 属性,既可以在模板中直接使用,也可以通过 setup 函数的 props 参数获取。需要注意的是, props 是一个 Proxy 对象。

3,setup 函数的参数 2:context

(1)setup 函数第二个参数是 context,该参数对象包含以下三个属性:
  • attrs:所有非 prop 的属性(attribute)。 
  • slots:父组件传递过来的插槽(slot)。 
  • emit:组件内部发送事件时用到的 emit 函数(setup 中不能访问 this,因此不可使用 this.$emit)。

(2)我们新建一个 SetupContext.vue 组件,代码如下所示:
  • 首先 setup 函数中添加第二个参数 context
  • 接着,在 setup 函数中分别打印 context 中的 attrsslotsemit 三个属性。 
<template>
  <div class="setup-context" style="border:1px solid #ddd;margin:10px">
    SetupContext组件
    <h4>{{ message }}</h4>
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  },
  /**参数一: props, 父组件传递过来属性*/
  /**参数二: context, Vue框架传递过来上下文*/
  setup(props, context) {
    console.log(props.message); // 所有prop的attribute
    // 所有的非prop的attribute
    console.log(context.attrs.id, context.attrs.class);
    console.log(context.slots); // 父组件传递过来的插槽
    console.log(context.emit); // 用来触发事件的emit
  }
}
</script>
<template>
  <div class="setup-context" style="border:1px solid #ddd;margin:10px">
    SetupContext组件
    <h4>{{ message }}</h4>
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  },
  /**参数一: props, 父组件传递过来属性*/
  /**参数二: context, Vue框架传递过来上下文(context 对象支持解构)*/
  setup(props, { attrs, slots, emit }) {
    console.log(props.message); // 所有prop的attribute
    // 所有的非prop的attribute
    console.log(attrs.id, attrs.class);
    console.log(slots);
    console.log(emit);
  }
}
</script>

(3)修改 App.vue 组件,向 <setup-context> 组件传递 props 和非 props 属性。
<template>
    <div class="app" style="border:1px solid #ddd;margin:4px">
        App组件
        <setup-context message="学习setup context参数" id="code" class="hangge"></setup-context>
    </div>
</template>

<script>
import SetupContext from './SetupContext.vue';
export default {
    components: {
        SetupContext
    }
}
</script>

(4)运行效果如下下图所示,可以正常获取和打印 attrsslotsemit 属性。 

4,setup 函数的返回值

(1)setup 函数不仅可以接收 propscontext 参数,还可以像普通函数一样有返回值。具体而言,setup 函数可以返回一个对象类型的值,该值可以直接在模板(template)中使用。这意味着我们可以使用 setup 函数的返回值代替 data 选项的返回值。 

(2)新建 SetupReturm.vue 组件,代码如下:
  • setup 函数返回一个对象,该对象中包含一个 counter 变量和一个 increment 函数。这两个属性可以直接在模板中使用。我们可以将 counter 变量绑定到 <h4> 元素上,以显示当前计数。 
  • 同时,我们还可以将 increment 函数绑定到 <button> 元素的 click 事件上,以在单击按钮时增加计数器的值。 
<template>
  <div class="setup-return" style="border:1px solid #ddd;margin:10px">
    SetupReturn组件
    <h4>当前计数: {{counter}}</h4>
    <button @click="increment">+1</button>
  </div>
</template>

<script>
  export default {
    setup(props, context) {
      // 局部变量
      let counter = 100;
      // 局部函数
      const increment = () => {
        counter++;
        console.log(counter);
      }
      // 返回值( 返回的属性可以直接在template中使用 )
      return {
        counter:counter, // 返回一个内部变量
        increment:increment // 返回一个方法/函数
      }
    }
  }
</script>

(3)修改 App.vue 组件,代码如下所示:
<template>
  <div class="app" style="border:1px solid #ddd;margin:4px">
    App组件
    <setup-return></setup-return>
  </div>
</template>

<script>
import SetupReturn from './SetupReturn.vue';
export default {
  components: {
    SetupReturn
  }
}
</script>

(4)运行效果如下,可以看到 counter 的值显示出来了,当单击“+1”按钮时,会回调 increment 函数来修改 counter 变量,但是页面的数值并未响应式刷新。因为 counter 是一个普通的变量,默认情况下, Vue.js 3 并不会跟踪它的变化,所以页面没有响应式刷新。
提示:我们可以使用 Vue.js 3 提供的响应式 API 实现响应式的 counter 变量,具体见下文。
评论

全部评论(0)

回到顶部