【Vue进阶学习笔记】组合式API(Composition API)

发布于:2025-07-18 ⋅ 阅读:(22) ⋅ 点赞:(0)

setup 选项

Vue3 引入了全新的 setup 选项,用于定义组件的初始状态和核心逻辑。
setup 函数采用 Composition API 的方式组织代码,显著提升了代码的可读性和灵活性。该函数接收 propscontext 两个参数,并返回一个包含响应式状态和方法的对象,这些内容可直接在模板中使用。
这种设计不仅使组件结构更加清晰明了,还为逻辑复用提供了更好的支持。
原始复杂写法

<script>
export default {
  setup() {
    //数据
    const message = 'Hello Vue 3!'
    //函数
    const sayHello = () => {
      console.log(message)
    }
    //返回数据和函数
    return {
      message,
      sayHello
    }
  }
}
</script>

语法糖写法

<script setup>
  const message = 'Hello Vue 3!'
  const sayHello = () => {
    console.log(message)
  }
</script>

reactive和ref函数

reactive()

作用:接受对象类型数据的参数传入并返回一个响应式的对象
核心步骤

<script setup>
import { reactive } from 'vue'
const state = reactive(对象类型数据)
</script>
  1. 从 vue 包中导入 reactive 函数

ref()

作用:接受任意类型数据的参数传入并返回一个响应式且可变的ref对象,通过.value属性访问和修改内部值。适用于基本类型数据和对象引用。更推荐使用ref(),因为在功能上覆盖了reactive()

核心步骤

<script setup>
import { ref } from 'vue'
const count = ref(简单类型或者复杂类型数据) // 基本类型
</script>

示例-计数器按钮

<template>
  <button @click="buttonClick">{{ count }}</button>
</template>

<script setup>
  import { ref } from 'vue'
  const count = ref(0)
  function buttonClick(){
    count.value++
  }
</script>

computed 计算属性函数

计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法

<script setup>
import { computed } from 'vue'
const computedState = computed(() => {
	return 基于响应式数据做计算之后的值
})
</script>
  1. 导入computed函数
  2. 执行函数,在回调参数中return基于响应式数据做计算的值,用变量接收

示例-过滤数组

<template>
  <div>原始响应式数组 - {{ list }}</div>
  <div>过滤后响应式数组 - {{ computedList }}</div>
</template>

<script setup>
import { ref, computed } from 'vue';
const list = ref([1, 2, 3, 4, 5, 6, 7, 8]);
const computedList = computed(() => {
  return list.value.filter(item => item > 2);
});
</script>

watch 函数

作用:侦听一个或者多个数据的变化,数据变化时执行回调函数
两个额外参数:1.immediate(立即执行)2.deep(深度侦听)

基础使用 - 侦听单个数据

  1. 导入watch函数
  2. 执行watch函数传入要侦听的响应式数据(ref对象)和回调函数
<script setup>
// 1. 导入watch
import { ref, watch } from 'vue'
const count = ref(0)

// 2. 调用watch 侦听变化
watch(count, (newValue, oldValue) => {
  console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
</script>

基础使用 - 侦听多个数据

说明:同时侦听多个响应式数据的变化,不管哪个数据变化都需要执行回调

<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('cp')
// 侦听多个数据源
watch(
  [count, name],
  ([newCount, newName], [oldCount, oldName]) => {
    console.log('count或者name变化了', [newCount, newName], [oldCount, oldName])
  }
)
</script>

deep 深度监听机制

在 Vue 的响应式系统中,通过 watch 监听的 ref 对象默认采用浅层侦听(shallow watch)机制。这意味着当直接修改嵌套的对象属性时,默认不会触发 watch 回调函数执行。

默认浅层监听的问题

const state = ref({ count: 0 })

// 默认浅层监听
watch(state, () => {
  console.log('数据变化了') // 不会触发
})

const changeStateByCount = () => {
  // 直接修改嵌套属性 - 不会触发回调
  state.value.count++
}

在这个例子中,当我们修改 state.value.count 时,watch 回调不会执行,因为:

  1. ref 对象本身(state)的引用没有改变
  2. 默认的浅层监听不会追踪嵌套属性的变化

解决方案:开启 deep 选项

要实现深度监听,需要显式设置 deep: true 选项:

watch(
  state,
  () => {
    console.log('深度监听:数据变化了')
  },
  { deep: true } // 启用深度监听
)

开启深度监听后,watch 会:

  1. 递归追踪所有嵌套属性的变化
  2. 无论修改哪一层级的属性都会触发回调
  3. 注意性能开销,因为要追踪的对象可能很大

生命周期函数

Vue3的生命周期API(选项式VS组合式)

选项式 API 组合式 API
beforeCreate/created setup
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted

生命周期函数基本使用

  1. 导入生命周期函数
  2. 执行生命周期函数 传入回调
import { onMounted } from 'vue'
onMounted(() =? {
	//自定义逻辑
})

父子通信

父传子

同样是通过props实现,在vue3中有更简洁的写法:通过defineProps()往里面传入数组或对象来接受父级传来的数据

<script setup> 
const props = defineProps({
	message:String,
	count:Number
})
</script>

以下是一个示例
父组件

<template>
  <div class="box">
    <h1>props:我是父组件曹操</h1>
    <hr />
    <Child info="我是曹操" :money="money"></Child>
  </div>
</template>

<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>

<style scoped>
.box {
  width: 100vw;
  height: 400px;
  background: yellowgreen;
}
</style>

子组件

<template>
  <div class="son">
       <h1>我是子组件:曹植</h1>
       <p>{{info}}</p>
       <p>{{money}}</p>
       <button @click="updateProps">修改props数据</button>
  </div>
</template>

<script setup lang="ts">
//需要使用到defineProps方法去接受父组件传递过来的数据
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
//按钮点击的回调
const updateProps = ()=>{
  // props.money+=10;  props:只读的
  console.log(props.info)
}
</script>

<style scoped>
.son{
  width: 400px;
  height: 200px;
  background: hotpink;
}
</style>

在这里插入图片描述

子传父

基本思想

  1. 父组件中给子组件标签通过@绑定事件
  2. 子组件内部通过$emit方法触发事件

父组件

<script setup>
// 引入子组件
import sonComVue from './son-com.vue'
const getMessage = (msg) => {
  console.log(msg)
}
</script>

<template>
  <!-- 1. 绑定自定义事件 -->
  <sonComVue @get-message="getMessage" />
</template>

子组件

<script setup>
// 2. 通过 defineEmits 编译器宏生成 emit 方法,以数组传入要生成的事件名称
const emit = defineEmits(['get-message'])
const sendMsg = () => {
  // 3. 触发自定义事件 并传递参数
  emit('get-message', 'this is son msg')
}
</script>

<template>
  <button @click="sendMsg">sendMsg</button>
</template>

模板引用

通过ref标识获取真实的dom对象或者组件实例对象

如何使用(以获取dom为例 组件同理)

<template>
  <!-- 2. 通过ref标识绑定ref对象 -->
  <h1 ref="h1Ref">我是dom标签h1</h1>
</template>
<script setup>
import { ref } from 'vue'
// 1. 调用ref函数得到ref对象
const h1Ref = ref(null)
</script>

defineExpose()

默认情况下在

<script setup>
import { ref } from 'vue'
const testMessage = ref('this is test msg')
defineExpose({
  testMessage
})
</script>

provide 和 inject

作用和场景

provideinject 是 Vue.js 中用于实现跨层级组件通信的一对 API,主要用于解决组件多层嵌套时的数据传递问题。它们的作用是允许祖先组件向其所有后代组件(无论嵌套多深)传递数据和方法,而不需要逐层通过 props 传递。

典型应用场景包括:

  1. 主题切换功能(深层次子组件需要访问主题变量)
  2. 国际化实现(所有组件都需要语言包)
  3. 用户权限管理(深层组件需要判断权限)
  4. 全局状态共享(替代 Vuex 的轻量级方案)

跨层传递响应式数据

在 Vue 3 中,为了确保传递的数据保持响应式,需要在调用 provide 函数时将第二个参数设置为 ref 对象或 reactive 对象。这样当数据变化时,所有注入该数据的组件都能自动更新。

基本用法

顶层组件(提供数据)

import { ref, provide } from 'vue'

export default {
  setup() {
    // 创建响应式数据
    const count = ref(0)
    const userInfo = reactive({
      name: '张三',
      age: 25
    })
    
    // 提供数据给后代组件
    provide('count-key', count)
    provide('user-info-key', userInfo)
    
    // 也可以提供方法
    const increment = () => {
      count.value++
    }
    provide('increment-method', increment)
    
    return { count }
  }
}

底层组件(注入数据)

import { inject } from 'vue'

export default {
  setup() {
    // 注入数据
    const count = inject('count-key')
    const userInfo = inject('user-info-key')
    const increment = inject('increment-method')
    
    // 可以设置默认值
    const theme = inject('theme', 'light')
    
    // 如果确定提供者会提供数据,可以使用非空断言
    const requiredData = inject('required-key')!
    
    return { count, userInfo, increment, theme }
  }
}

网站公告

今日签到

点亮在社区的每一天
去签到