Vue3组合式Api快速入门
一、🍕组合式API入口-setup
1. setup选项的写法和执行时机
<script>
export default {
setup(){
//code
}
}
</script>
在组件进行渲染时会优先执行setup函数,其执行时期是先于beforeCreate之前。
代码案例
<template>
<div>
main
</div>
</template>
<script>
export default {
setup(){
console.log("setup")
},
beforeCreate() {
console.log("beforeCreate")
}
}
</script>
2. 如何使用setup函数
<template>
<div>
{{ message }}
</div>
<button @click="clikfunc">这是个按钮</button>
</template>
<script>
export default {
setup() {
const message = "这是一条信息"
const clikfunc = () => {
console.log("按钮被点击",this)
};
return {
message,
clikfunc
}
}
}
</script>
在setup函数中的数据和方法必须要return出去才能够使用,其中已经没有了this关键字,因vue3语法风格的问题,已经不推荐使用this这个关键字进行数据更改,在setup中打印this也会得到一个undefine,可见this并没有指向组件实例。
3. <script setup>语法糖
在定义了许多变量或者函数时,如果每一个变量和函数都需要return的话,会显的代码十分的冗余,所以就有了<script setup>这种语法糖写法,直接定义,直接使用,日后开发大部分都是这种写法。
语法糖写法(实现效果与上图一致)
<template>
<div>
{{ message }}
</div>
<button @click="clikfunc">这是个按钮</button>
</template>
<script setup>
const message = "这是一条信息"
const clikfunc = () => {
console.log("按钮被点击")
}
</script>
二、🍔组合式API-reactive和ref函数
这两个函数都是类似vue2中的data一样,用于生成响应式数据
1. reactive函数
reactive():接受对象类型数据的参数传入并返回一个响应式的对象
<template>
<button @click="setCount">{{ state.count }}</button>
</template>
<script setup>
//1.导入函数
import {reactive} from "vue";
//2.执行函数 传入一个对象类型的参数,并使用变量接收
const state = reactive({
count: 0
})
const setCount = () => {
state.count++
}
</script>
2. ref函数
ref():接收==简单类型==或者==对象类型==的数据传入并返回一个响应式的对象
提示:ref函数是简单类型和对象类型都可以接受,reactive函数只能接受对象类型
<template>
<button @click="setCount">{{ count }}</button>
</template>
<script setup>
//1.导入函数
import {ref} from "vue";
//2.执行函数 传入一个对象类型的参数,并使用变量接收
const count = ref(0)
const setCount = () => {
//在脚本区域修改由ref产生的响应式数据,必须通过.value属性
count.value++
}
</script>
打印count,可以发现ref产生的是一个响应式的对象
三、🍟组合式API-computed
computed():计算属性的思想与vue2的是完全一致的,组合式API下只是修改了写法
<template>
<div>原始的数组-{{ org_list }}</div>
<div>过滤后的数组-{{ new_list }}</div>
</template>
<script setup>
//1.导入computed函数
import {ref} from "vue";
import {computed} from "vue";
const org_list = ref([1, 2, 3, 4, 5, 6, 7, 8])
//2.执行函数return计算后的值 变量接收
const new_list = computed(() => {
return org_list.value.filter(item => item > 2)
})
setTimeout(() => {
org_list.value.push(9,10)
}, 3000)
</script>
提示:
计算属性中不应该有异步请求,修改DOM这些操作,同时避免直接修改计算属性的值,计算属性应该是只读的
四、🌭组合式API-watch
watch的作用与vue2中是一致的,侦听一个或者多个数据的变化,数据变化时执行回调函数
额外的两个参数:
- immediate(立即执行)
- deep(深度侦听)
1. 基础使用-单个数据的侦听
<template>
<button @click="setCount">{{ count }}</button>
</template>
<script setup>
//1.导入watch
import {ref, watch} from "vue";
const count = ref(0)
const setCount = () => {
count.value++
}
//2.调用watch 侦听变化
//此处的ref对象不加.value
watch(count, (newValue, oldVale) => {
console.log(`count发生了变化,旧值为${oldVale},新值为${newValue}`)
})
</script>
2. 基础使用-多个数据的侦听
同时侦听多个数据的变化,不管哪个数据变化都需要执行回调
<template>
<button @click="setCount">{{ count }}</button><br>
<button @click="setName">{{ name }}</button>
</template>
<script setup>
//1.导入watch
import {ref, watch} from "vue";
//创建两个响应式数据
const count = ref(0)
const name = ref("test")
const setCount = () => {
count.value++
}
const setName = () => {
name.value="test被修改了"
}
//2.调用watch 侦听变化
//此处的ref对象不加.value
watch([count,name], ([newCount,newName], [oldCount,oldName]) => {
console.log(`count发生了变化,旧值为${oldCount},新值为${newCount}`)
console.log(`name发生了变化,旧值为${oldName},新值为${newName}`)
})
</script>
无论点击哪个按钮,都会执行回调函数
3. immediate选项
在某些情况下,我们可能需要在组件初始化阶段就立即执行侦听器,以获取某些初始数据或执行某些操作,这个时候便可开启immediate选项
<template>
<button @click="setCount">{{ count }}</button>
<br>
</template>
<script setup>
//1.导入watch
import {ref, watch} from "vue";
const count = ref(0)
const setCount = () => {
count.value++
}
watch(count, () => {
console.log("该监听器已被创建")
}, {immediate: true})
</script>
在侦听器创建时(页面刷新时)立即触发回调,响应式数据变化之后继续执行回调
4. deep选项
通过watch监听的ref对象默认是浅层侦听,直接修改嵌套的对象属性不会触发回调执行,你需要监听一个由ref产生的对象类型的响应式数据的属性值时,需要开启deep选项。
没有开启deep选项时
<template>
<button @click="setCount">{{ state.count }}</button>
<br>
</template>
<script setup>
//1.导入watch
import {ref, watch} from "vue";
const state = ref({count: 0})
const setCount = () => {
state.value.count++
}
watch(state, () => {
console.log("数据发生了变化")
})
</script>
数据会修改,但是没有执行回调函数
开启deep选项
//与上述代码一致,只是在watch中开启deep选项
watch(state, () => {
console.log("数据发生了变化")
},{deep:true})
开启过后,执行了回调函数并打印了语句
5. 精确监听
当你开启deep选项时,就会递归遍历,监听对象的所有属性都会被监听,特别是在处理大型对象或频繁更新的对象时,会造成性能浪费。
<template>
<div>当前的名字为:{{ info.name }}</div>
<br>
<div>当前的年龄为:{{ info.age }}</div>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<br>
</template>
<script setup>
import {ref, watch} from "vue";
const info = ref({name: '张三', age: 18})
const changeName = () => {
info.value.name = "李四"
}
const changeAge = () => {
info.value.age = 68
}
//不开启deep选项,精确监听age属性
watch(
() => info.value.age,
() => console.log("age发生变化了")
)
</script>
修改name时,控制台没有变化,修改age时,监听到变化,执行回调函数,打印了语句
五、🍿组合式API-生命周期函数
Vue的生命周期指的是Vue实例从创建到销毁的过程,包括开始创建、初始化数据、编译模板、挂载Dom→数据更新→再次编译模板、再次挂载Dom等过程。这个过程总共分为8个阶段:创建前/后,载入前/后,更新前/后和销毁前/后。
官网的生命周期图(组合式)
==Vue3的生命周期API(选项式 VS 组合式)==
选项式API | 组合式API |
---|---|
beforeCreate/created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
以onMounted函数为例
<template>
<div>onMounted</div>
</template>
<script setup>
//1.导入
import {onMounted} from "vue";
//2.执行函数
onMounted(()=>{
console.log("组件挂载完毕")
})
</script>
生命周期函数是可以多次执行的,多次执行时传入的回调会在时机成熟时依次执行
<template>
<div>onMounted</div>
</template>
<script setup>
//1.导入
import {onMounted} from "vue";
//2.执行函数
onMounted(()=>{
console.log("onMounted1")
})
onMounted(()=>{
console.log("onMounted2")
})
</script>
当在一个onMounted中有大量的代码的时候,可以再写一个onMounted进行补充逻辑,换句话说就是,不敢动屎代码的时候,加上去就完事了。
六、🧂组合式API-父子组件通信
1. 父传子
基本思想:
- 父组件给子组件绑定属性
- 子组件内部通过props选项接收
传入响应式的数据
2. 子传父
基本思想:
- 父组件中给子组件标签通过@绑定事件
- 子组件内部通过$emit方法触发事件
3. 解决报错
在这一章节中,遇到了两个问题,一个是defineProps没有被定义,一个是组件名称命名问题,这两个问题都是Eslint检测的出的问题
'defineProps' is not defined no-undefine
直接引入就行,或者关闭Eslint
import {defineProps} from "vue";
Component name "xxx" should always be multi-word
在组件命名的时候未按照 ESLint 的官方代码规范进行命名,根据 ESLint 官方代码风格指南,除了根组件(App.vue)以外,其他自定义组件命名要使用大驼峰命名方式或者用“-”连接单词进行命名,遇到该问题时重命名就行了;
七、🍳组合式API-模板引用
通过red标识获取真实的dom对象或者组件实例对象
<template>
<!--2。通过ref标识绑定ref对象-->
<h1 ref="h1Ref">这是一个标签</h1>
<TestCom ref="testComRef"/>
</template>
<script setup>
import {onMounted, ref} from "vue";
import TestCom from "@/components/TestCom";
//1. 调用ref函数
const h1Ref = ref(null)
const testComRef = ref(null)
//组件挂载完毕后才能够获取
onMounted(()=>{
console.log(h1Ref.value)
console.log(testComRef.value)
})
</script>
1.difineExpose函数
在自定义组件<TestCom/>中,有内部属性和方法,但是,打印出来的实例对象中却没有,默认情况下在<script setup>==语法糖下组件内部的属性和方法是不开放给父组件访问==的,所以可以通过defineExpose编译宏指定哪些属性和方法允许访问。这样设计的主要原因是防止错误修改。
<template>
<div>这是TestCom组件</div>
</template>
<script setup>
import {ref, defineExpose} from "vue";
const name = ref("test name")
const setName = () => { // eslint-disable-line no-unused-vars
name.value = "new name"
}
//暴露子组件的属性
defineExpose({
name
})
</script>
八、🥐组合式API-provide和inject
作用:顶层组件向任意底层组件传递数据和方法,实现跨层组件通信
此处传的静态数据
传响应式数据,在调用provider时,将第二个参数设置为ref对象
顶层传递方法:
注意:谁的数据谁负责修改。
总结
由于本人也是初次系统的学习Vue3的组合式API,所以文中可能有缺漏或有误的知识点,如果您知道的话,望在评论区指出。
转载自:https://juejin.cn/post/7271131410377949238