当前位置: 首页 > news >正文

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

目录

  • setup 选项
  • reactive和ref函数
    • reactive()
    • ref()
    • 示例-计数器按钮
  • computed 计算属性函数
    • 示例-过滤数组
  • watch 函数
    • 基础使用 - 侦听单个数据
    • 基础使用 - 侦听多个数据
    • deep 深度监听机制
      • 默认浅层监听的问题
      • 解决方案:开启 deep 选项
  • 生命周期函数
    • Vue3的生命周期API(选项式VS组合式)
    • 生命周期函数基本使用
  • 父子通信
    • 父传子
    • 子传父
  • 模板引用
    • 如何使用(以获取dom为例 组件同理)
    • defineExpose()
  • provide 和 inject
    • 作用和场景
    • 跨层传递响应式数据
      • 基本用法

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/createdsetup
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted

生命周期函数基本使用

  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 }}
}
http://www.dtcms.com/a/284430.html

相关文章:

  • Go 程序无法使用 /etc/resolv.conf 的 DNS 配置排查记录
  • React hooks——memo
  • 【软件开发】主流 AI 编码插件
  • 关于el-table异步获取数据渲染动态列数据赋值列数据渲染时title高度异常闪过问题
  • 深度解析:基于EasyX的C++黑白棋AI实现 | 算法核心+图形化实战
  • 数据呈现进阶:漏斗图与雷达图的实战指南
  • 基于Echarts的气象数据可视化网站系统的设计与实现(Python版)
  • Idea使用git不提示账号密码登录,而是输入token问题解决
  • 【解决方案】yakit流量转发到mitmproxy
  • 浅谈 awk 中管道的用法
  • zynq mpsoc switch级联ssd高速存储方案
  • 贴吧项目总结二
  • mysql——搭建MGR集群
  • CommonJS 功能介绍
  • 基于dcmtk的dicom工具 第二章 图像接受StoreSCP(2)
  • Python Day16
  • Java行为型模式---备忘录模式
  • 从零开始的云计算生活——第三十三天,关山阻隔,ELK日志分析
  • rtp传输推流h265
  • Unity使用GTCRN实现流式语音增强
  • SpringBoot一Web Flux、函数式Web请求的使用、和传统注解@Controller + @RequestMapping的区别
  • 探微“元宇宙”:概念内涵、形态发展与演变机理
  • CSS面试题及详细答案140道之(41-60)
  • Kiro AI IDE上手初体验!亚马逊出品,能否撼动Cursor的王座?
  • Amazon S3成本优化完全指南:从入门到精通
  • 8 几何叠加分析
  • 系统设计时平衡超时时间与多因素认证(MFA)带来的用户体验下降
  • 量子计算的安全与伦理:当技术革命叩击数字时代的潘多拉魔盒
  • sqli-labs靶场通关笔记:第25-26a关 and、or、空格和注释符多重过滤
  • 4G模块 A7680通过MQTT协议连接到腾讯云