Vue3组合式API

news/2024/10/29 1:24:33/

目录

composition API vs options API

体验 composition API

setup 函数

reactive 函数

ref 函数

script setup 语法

计算属性 computed 函数

监听器 watch 函数

生命周期

模板中 ref 的使用

组件通讯 - 父传子

组件通讯 - 子传父

依赖注入 - provide 和 inject

保持响应式 - toRefs 函数


​​​​​​​composition API vs options API

  1. vue2 采用的就是 options API

    (1) 优点: 易于学习和使用, 每个代码有着明确的位置 (例如: 数据放 data 中, 方法放 methods 中)

    (2) 缺点: 完成相同功能的代码不能放在一起, 在大项目中尤为明显。可维护性不好

  2. vue3 新增的就是 composition API

    (1) compositionAPI 是基于 逻辑功能 组织代码的, 一个功能相关的代码可以放到一起

    (2) 即使项目大了, 功能多了,也能快速定位相关功能的代码,大大的提升了代码的可维护性

  3. vue3 推荐使用 composition API, 也保留了options API

    即就算不用 composition API, 用 vue2 的写法也完全兼容!!

体验 composition API

需求:

  1. 显示隐藏图片

  2. 计数器功能

 options API 版本

<template><button @click="toggle">显示隐藏图片</button><img v-show="show" alt="Vue logo" src="./assets/vue.svg" /><hr />计数器:{{ count }} <button @click="add">+1</button>
</template>
<script>
export default {data() {return {show: true,count: 0}},methods: {toggle() {this.show = !this.show},add() {this.count++}}
}
</script>

composition API 版本

<template><button @click="toggle">显示隐藏图片</button><img v-show="show" alt="Vue logo" src="./assets/vue.svg" /><hr />计数器:{{ count }} <button @click="add">+1</button>
</template>
<script>
// ref 就是一个组合式API,用于数据响应式 
import { ref } from 'vue';
export default {setup () {// 显示隐藏图片const show = ref(true)const toggle = () => {show.value = !show.value}// 计数器const count = ref(0)const add = () => {count.value++}return { show, toggle, count, add }}
}
</script>

小结:

optionsAPI

  • 优点: 易于学习和使用, 每个代码有着明确的位置

  • 缺点: 完成相同功能的代码不能放在一起, 在大项目中尤为明显。可维护性不好

compositionAPI

  • 基于 逻辑功能 组织代码

  • 可复用性和可维护性都更好!

setup 函数

composition api 的使用, 需要配置一个 setup 函数

  1. setup 函数是一个新的组件选项, 作为组件中 composition API 的起点

  2. setup 比 beforeCreate 执行时机还要早,此时 vue 的实例还没有创建,所以setup 中不能使用 this, this 指向 undefined

  3. 在模版中需要使用的数据和函数,需要在 setup 返回

<template><h1 @click="sayHi">{{msg}}</h1>
</template><script>
export default {setup () {console.log('setup')console.log(this)// 定义数据和函数const msg = 'hi vue3'const sayHi = () => {console.log(msg)}return { msg, say }},beforeCreate() {console.log('beforeCreate')console.log(this)}
}
</script>

reactive 函数

setup 中定义的数据,默认情况不是响应式的,需要用 reactive 函数,将数据变成响应式的

作用:可以将一个复杂类型的数据,转换成响应式数据

<template><div>{{ user.name }}</div><div>{{ user.age }}</div><button @click="changeAge">改年龄</button>
</template><script>
import { reactive } from 'vue'export default {setup () {const user = reactive({name: 'zs',age: 18})const changeAge = () => {user.age++console.log(user.age)}return {user,changeAge}}
}
</script>

ref 函数

reactive 处理的数据,必须是复杂类型,如果是简单类型无法处理成响应式,所以有 ref 函数!

作用:可以将一个简单类型或复杂类型的数据,转换成响应式数据。

<template><div>{{ count }}</div><button @click="add">+1</button>
</template><script>
import { ref } from 'vue'export default {setup() {const count = ref(0)console.log(count)console.log(count.value)const add = () => {count.value++}return {count,add}}
}
</script>

ref 和 reactive 的最佳使用方式:

  • 明确的对象,明确的属性,用 reactive,其他用 ref

  • 从vue3.2之后,更推荐使用 ref(ref底层性能做了提升 => 260%)

// 1. 明确的对象和属性
const form = reactive({username: '',password: ''
})// 2. 不明确的对象和属性
const list = ref([])
const res = await axios.get('/list')
list.value = res.data

script setup 语法

script setup 是在单文件组件 (SFC) 中,使用组合式 API 的编译时语法糖。相比于普通的 script 语法更加简洁

要使用这个语法,需要将 setup attribute 添加到 <script> 代码块上:

<script setup></script>

所有定义的变量,函数和 import 导入的内容都可以直接在模板中直接使用

<template><div>{{ count }}</div><button @click="add">+1</button>
</template><script setup>
import { ref } from 'vue'const count = ref(0)
const add = () => {count.value++
}
</script>

计算属性 computed 函数

computed 函数调用时,要接收一个处理函数,处理函数中,需要返回计算属性的值。

<template><div>今年的年龄 <input type="number" v-model="age" /></div><div>明年的年龄 {{ nextAge }}</div>
</template><script setup>
import { computed, ref } from 'vue'const age = ref(18)
const nextAge = computed(() => {return age.value + 1
})
</script>

监听器 watch 函数

watch 监听, 接收三个参数
1. 参数1: 监视的数据
2. 参数2: 回调函数
3. 参数3: 额外的配置

<template><div>{{ count }} <button @click="count++">+1</button></div><div>{{ user }} <button @click="changeUser">修改用户信息</button><button @click="changeName">修改用户的年龄</button><button @click="changeAge">修改用户的姓名</button></div>
</template><script setup>
import { ref, watch } from 'vue'// 1. 监听数据基础用法
const count = ref(0)
watch(count, (newValue, oldValue) => {console.log(newValue, oldValue)
})// 2. 监听复杂类型数据
const user = ref({name: 'zs',age: 18
})
const changeUser = () => {user.value = {name: 'ls',age: 19}
}
const changeName = () => {user.value.name = 'ls'
}
watch(user, (newValue) => {console.log('user变化了', newValue)
}, {// 深度监听:当监听复杂数据类型的某个属性的变化,需要深度监听deep: true,// 让监听器立即执行一次immediate: true
})// 3. 监听对象的某个属性的变化
const changeAge = () => {user.value.age = 19
}
watch(() => user.value.age,(newValue) => {console.log(newValue)}
)
</script>

生命周期

生命周期函数 vue3 中的生命周期函数, 需要在 setup 中调用。

vue2 和 vue3 的生命周期对比:

  1. beforeCreate 和 created 在 setup 中不需要,原来在这两个生命周期中做的事,直接写到setup函数中。

  2. 在原来的名字前加一个 on

  3. beforeDestroyed 变为 onBeforeUnmount,destroyed 变为 onUnmounted

选项式API下的生命周期函数使用组合式API下的生命周期函数使用
beforeCreate不需要(直接写到setup函数中)
created不需要(直接写到setup函数中)
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyedonBeforeUnmount
destroyedonUnmounted
activatedonActivated
deactivatedonDeactivated

 

<script setup>
import { onMounted } from "vue"// 生命周期函数:组件渲染完毕
onMounted(()=>{console.log('onMounted触发了')
})onMounted(()=>{console.log('onMounted也触发了')
})
</script><template><div>生命周期函数</div>
</template>

模板中 ref 的使用

联想之前的 ref 和 $refs, 获取 DOM 元素 或 组件

获取 DOM

  1. 创建 ref => const h1Ref = ref(null)

  2. 模板中建立关联 => <h1 ref="h1Ref">钩子函数-----123</h1>

  3. 使用 => hRef.value 来获取 DOM

<script setup>
import { ref, onMounted } from 'vue'const h1Ref = ref(null) onMounted(() => {console.log(h1Ref.value)
})
</script><template><h1 ref="h1Ref">我是标题</h1>
</template>

获取组件实例

<script setup>
import { ref } from 'vue'
import MyForm from './components/MyForm.vue'const myFormRef = ref(null)const fn = () => {console.log(myFormRef.value.count)myFormRef.value.validate()
}
</script><template><MyForm ref="myFormRef"></MyForm><button @click="fn">获取子	组件属性和方法</button>
</template>

需要使用 defineExpose 暴露属性或方法

<script setup>
import { ref } from 'vue'const count = ref(0)
const validate = () => {console.log('表单校验方法')
}
// 暴露属性或方法给外部组件使用
defineExpose({count,validate
})
</script><template><h3>我是 Form 组件</h3>
</template>

组件通讯 - 父传子

目标:能够实现组件通讯中的父传子组件通讯

步骤:

  1. 父组件提供数据

  2. 父组件将数据传递给子组件

  3. 子组件通过 defineProps 进行接收

核心代码:

父组件

<script setup>
import { ref } from 'vue'
// 在 setup 语法中,组件导入之后就能够直接使用,不需要使用 components 进行局部注册
import Child from './components/Child.vue'const car = ref('宝马')
</script><template><div style="border: 3px solid #ccc;margin: 10px;"><h1>我是父组件</h1><Child :car="car"></Child></div>
</template>

子组件

<script setup>
// defineProps: 接收父组件传递的数据
const props = defineProps({car: {type: String,required: true// default: '奔驰'}
})
// 如果使用 defineProps 接收数据,这个数据只能在模板中渲染,如果想要在 script 中使用 props 属性,应该接收返回值。
console.log(props.car)
</script><template><div style="border: 3px solid #ccc;margin: 10px;"><h3>我是子组件</h3><div>{{ car }}</div></div>
</template>

组件通讯 - 子传父

目标:能够实现组件通讯中的子传父

步骤:

  1. 父组件通过自定义事件的方式在子组件上注册事件

  2. 父组件提供自定义事件的处理函数,并接收子组件传递的数据

  3. 子组件通过 defineEmits 获取 emit 对象(因为没有 this)

  4. 子组件通过 emit 触发事件,并且传递数据

核心代码

父组件

<script setup>
import { ref } from 'vue'
import Child from './components/Child.vue'const car = ref('宝马')const changeCar = (newCar) => {car.value = newCar
}
</script><Child :car="car" @changeCar="changeCar"></Child>

子组件

<script setup>
defineProps({car: {type: String,required: true// default: '奔驰'}
})const emit = defineEmits(['changeCar'])const change = () => {emit('changeCar', '玛莎拉蒂')
}
</script><template><div style="border: 3px solid #ccc;margin: 10px;"><h3>我是子组件</h3><div>{{ car }}</div><button @click="change">换车</button></div>
</template>

依赖注入 - provide 和 inject

依赖注入:可以非常方便的实现跨级的组件通信

父组件利用 provide 提供数据

<script setup>
import { provide, ref } from 'vue'
import Child from './components/Child.vue'const car = ref('宝马')
provide('car', car)
</script><template><div style="border: 3px solid #ccc;margin: 10px;"><h1>我是父组件</h1><Child></Child></div>
</template>

子孙后代组件,都可以拿到这个数据)

<script setup>
import { inject } from 'vue'const car = inject('car')
</script>	<template><div style="border: 3px solid #ccc;margin: 10px;"><h3>我是子组件 -- {{ car }}</h3></div>
</template>

如果希望子传父, 可以 provide 传递一个方法

父组件

<script setup>
import { provide, ref } from 'vue'
import Child from './components/Child.vue'const car = ref('宝马')
const changeCar = (newCar) => {car.value = newCar
}
provide('car', car)
provide('changeCar', changeCar)
</script>

子组件

<script setup>
import { inject } from 'vue'const car = inject('car')
const changeCar = inject('changeCar')
</script><template><div style="border: 3px solid #ccc;margin: 10px;"><h3>我是子组件 -- {{ car }}</h3><button @click="changeCar('兰博基尼')">换车</button></div>
</template>

保持响应式 - toRefs 函数

如果对一个响应式数据, 进行解构, 会丢失它的响应式特性!

原因: vue3 底层是对 对象 进行监听劫持,reactive/ref 的响应式功能是赋值给对象的, 如果给对象解构, 会让数据丢失响应式的能力

toRefs 作用: 对一个 响应式对象 的所有内部属性, 都做响应式处理, 保证解构出的数据也是响应式的

<script setup>
import { ref, toRefs } from 'vue'
const user = ref({name: 'zs',age: 18
})
// 直接解构,会丢失响应式
const { name, age } = user.value
// 解构之前使用 toRefs 处理要解构的数据
const { name, age } = toRefs(user.value)
</script><template><div>{{ name }}</div><div>{{ age }}</div><button @click="name = 'ls'">改名</button><button @click="age++">改年龄</button>
</template>


http://www.ppmy.cn/news/57296.html

相关文章

点赋科技:本地生活,如何开启复苏之路

目前&#xff0c;全球经历这场前所未有的疫情大流行已经结束&#xff0c;尽管许多国家和地区的经济和社会都受到了影响。然而&#xff0c;做好本地生活的复苏规划和推进&#xff0c;将有助于在疫情之后尽快走出经济低迷期&#xff0c;恢复社会活动和生活体验。点赋科技将阐述如…

存储网络架构——DAS、NAS、SAN、分布式组网架构

目录 DAS直连式存储 NAS网络附加存储 SAN存储 存储区域网络 分布式存储组网 DAS直连式存储 DAS遇到的挑战 NAS网络附加存储 向主机提供文件服务&#xff1b;文件系统由存储设备维护&#xff0c;用户访问文件系统&#xff0c;不直接访问底层存储 拥有所有主机上文件与底层存储空…

BigInteger和BigDecimal

BigInteger 当一个整数很大&#xff0c;大到long都无法保存&#xff0c;就可以使用BigInteger这个类 使用方法&#xff1a;new import java.math.BigInteger;//记得引包 BigInteger bigInteger new BigInteger("33333333333399999999999");//用字符串传入 System…

【算法与数据结构】6 学会对算法进行性能测试

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于算法与数据结构体系专栏,本专栏对于0基础者极为友好,欢迎与我一起完成算法与数据结构的从0到1的跨越 算法性能测试 一、前情回顾二、算法性能测试1.生成测试用例2.使用测…

C语言:指针【进阶】习题练习及分析讲解

目录 一维数组关于strlen函数和sizeof()的练习整型数组字符数组指针 二维数组笔试题 前言&#xff1a; 前面我们刚刚学完了C语言&#xff1a;指针详解【进阶】的知识&#xff0c;这部分的知识还是要重在理解加实践&#xff0c;今天我这里就分享一些有关C语言指针方面的练习供大…

Security方法注解权限控制过程及自定义权限表达式

文章目录 使用内置的权限表达式PreAuthorizePermissionEvaluator 自定义权限表达式SysMethodSecurityExpressionHandler源码流程 SysMethodSecurityExpressionRoot 使用内置的权限表达式 PreAuthorize 这个用来判断超级管理员的话&#xff0c;还得在表达式上加上或 Permissi…

STL容器类

STL 1. STL初识 1.1 迭代器 1.1.1 原生指针也是迭代器 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; void test01() {int arr[5] { 1,2,3,4,5 };int* p arr;for (int i 0; i < 5; i) {cout << arr[i] << endl;cout &…

【Java笔试强训 24】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;年终奖 …