Vue组合式API--计算属性、生命周期、监听器、依赖注入、setup函数语法糖
常用的组合式API详解
一、setup中的computed(计算属性)
对于任何包含响应式数据的复杂逻辑,都应该使用计算属性。
在前面的Options API
(选项式API
)中,是使用computed
选项来完成计算属性的定义。
在Composition API
(组合式API
)中,我们可以在setup
函数中使用computed
方法来编写一个计算属性。
setup中如何使用computed:
1)基本写法
接收一个getter
函数,并为getter
函数返回的值,返回一个不变的ref
对象。
<template>
<h2>{{ fullname }}</h2>
<button @click="setFullname">设置fullname</button>
</template>
<script>
// 1. 引入computed
import { reactive, computed, ref } from 'vue'
export default {
setup() {
// 定义本地data数据
const names = reactive({
firstName: "jack",
lastName: "bryant"
})
// 2. 使用基本写法定义计算属性
const fullname = computed(() => {
return names.firstName + " " + names.lastName
})
console.log(fullname)
return {names, fullname, setFullname}
}
}
</script>
可以看到注意点有两个:
- 一定要先引入
computed
才能够在setup
函数中使用 - 给计算属性赋值时需要使用
.value
属性,因为它是一个ref
对象
2)监听多个计算属性
<template>
<div class="main">
<div class="bottom-info" :style="bottomInfo.style">
{{ bottomInfo.content }}
</div>
</div>
</template>
<script setup>
// 1.导入computed
import { computed } from 'vue';
// 2.定义计算属性
// const titleText = computed(() => {
// return props.itemData.verify_info.messages.join(" ")
// })
// const titleColor = computed(() => {
// return props.itemData.verify_info.text_color
// })
// 挨个写多个计算属性会有些麻烦,有着组合关系的一些计算属性可以写到一起
const bottomInfo = computed(() => {
return {
content: props.itemData.bottom_info.content,
style: {
color: props.itemData.bottom_info.content_color,
fontSize: props.itemData.bottom_info.font_size + "px"
}
}
})
</script>
3)完整语法
接收一个具有get
和set
的对象,返回一个可变的(可读写)ref
对象。
<template>
<h2>{{ fullname }}</h2>
<button @click="setFullname">设置fullname</button>
</template>
<script>
// 1. 引入computed
import { reactive, computed, ref } from 'vue'
export default {
setup() {
// 定义本地data数据
const names = reactive({
firstName: "jack",
lastName: "bryant"
})
// 2. 使用完整写法定义计算属性
const fullname = computed({
set: function(newValue) {
const tempNames = newValue.split(" ")
names.firstName = tempNames[0]
names.lastName = tempNames[1]
},
get: function() {
return names.firstName + " " + names.lastName
}
})
console.log(fullname)
// 3. 给计算属性赋值、此时会调用set方法去给names的firstName和lastName赋值
function setFullname() {
fullname.value = "lucy"
console.log(names)
}
return {names, fullname, setFullname}
}
}
</script>
二、setup中如何使用监听器
在组合式AP
I中,可以使用watchEffect
和watch
来完成响应式数据的侦听:
-
watchEffect
:用于自动收集响应式数据的依赖 -
watch
:需要手动指定侦听的数据源,数据变化时执行其回调函数默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调
2.1 watch
1) 监听一个数据源
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
})
watch(info, (newValue, oldValue) => {
console.log(newValue, oldValue)
})
2)监听多个数据源
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
})
const message = ref("Hello watch");
watch([info, message], (newValue, oldValue) => {
console.log(newValue, oldValue)
})
3) 关于深度监听和立即执行
默认情况下,组合式API
中的watch
函数就已经帮我们进行深度监听了。
当然也可以选择传入deep
显式指定。
而立即执行则需要传入immediate
显式指定。
const info = reactive({
name: "why",
age: 18,
friend: {
name: "kobe"
}
})
watch(info, (newValue, oldValue) => {
console.log(newValue, oldValue)
},{
immediate: true,
deep: true
})
2.2 watchEffect
1)基本使用
当监听到某些响应式数据变化时,我们希望执行某些操作,这个时候可以使用watchEffect
。
<script>
import { watchEffect, watch, ref } from 'vue'
export default {
setup() {
const counter = ref(0)
const name = ref("张三")
// 1.watchEffect传入的函数默认会直接被执行
// 2.在执行的过程中, 会自动的收集依赖(依赖哪些响应式的数据)
// 比如箭头函数中用到的counter和name,一旦发生变化,回调函数就会直接执行
const stopWatch = watchEffect(() => {
console.log("watchEffect", counter.value, name.value)
})
return {counter, name}
}
}
</script>
首先,watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖; 其次,只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行
2)停止监听
有时希望可以让watchEffect
停止侦听。此时可以获取watchEffect
的返回值函数,调用该函数即可。
<script>
import { watchEffect, watch, ref } from 'vue'
export default {
setup() {
const counter = ref(0)
const name = ref("张三")
// 只要调用watchEffect的返回值,就可以停止监听
const stopWatch = watchEffect(() => {
console.log("watchEffect", counter.value, name.value)
// counter.value > 10 时停止继续监听
if (counter.value >= 10) {
stopWatch()
}
})
return {counter, name}
}
}
</script>
2.3 watch/watchEffect区别
watch
必须制定数据源,watchEffect
自动收集依赖watch
监听到改变, 可以拿到改变前后value,watchEffect
只能拿到变化后的watchEffect
默认直接执行一次,watch
在不设置immediate
第一次是不执行
三、setup中如何使用ref获取元素或者组件
上一篇已经说过了如何使用ref
函数去定义响应式数据。
而Vue2.x
中的有一个通过ref
属性去获取DOM
元素或者组件。这在Vue3.x
的setup
函数中又是怎么做到的呢?
setup
函数中的方式是定义一个ref
对象,绑定到元素或者组件的ref
属性上即可。
<template>
<!-- 1.获取DOM元素 -->
<button ref="btnRef">按钮</button>
<!-- 2.获取组件实例 -->
<show-info ref="showInfoRef"></show-info>
<button @click="getElements">获取元素</button>
</template>
<script>
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
// 定义一个ref对象
const btnRef = ref()
const showInfoRef = ref()
// mounted的生命周期函数中就可以拿到相应的ref数据了
onMounted(() => {
// 完成之后btnRef就相当于之前的this.$refs.btnRef
console.log(btnRef.value)
console.log(showInfoRef.value)
})
function getElements() {
console.log(titleRef.value)
}
return {btnRef, showInfoRef, getElements}
}
}
</script>
四、setup中如何使用生命周期钩子
4.1 使用示例
<template>
<div></div>
</template>
<script>
// 1.引入函数onMounted
import { onMounted } from 'vue'
export default {
setup() {
// 2.注册生命周期函数
onMounted(() => {
console.log("onmounted")
})
}
}
</script>
使用起来就是先引入,然后在setup
函数中进行使用,需要接收一个函数对象,一般就要箭头函数。
4.2 选项式API
和组合式API
的对应关系
选项式API | setup中对应的组合式API |
---|---|
beforecreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeupdate | onBeforeupdate |
updated | onupdated |
beforeunmount | onBeforeunmount |
unmounted | onUnmounted |
activated | onActivated |
deactivated | onDeactivated |
4.3 为什么没有beforecreate和created对应的组合式API
因为setup
是围绕beforecreate
和created
生命周期钩子运行的,所以不需要显式地定义它们。
因此在这些钩子中编写的任何代码都可以直接在setup
函数中编写。
五、setup中如何使用依赖注入
5.1 Provide函数
provide
函数可以传入两个参数:
-
name:提供的属性名称;
-
value:提供的属性值
const name = ref("张三")
provide("name", name)
provide("age", 18)
为了增加 provide
值和 inject
值之间的响应性,我们可以在provide
值时使用ref
和reactive
。
就想这里的age
就不具备响应式。
5.2 Inject函数
在后代组件中可以通过inject
函数来注入需要的属性和对应的值.
Inject
函数可以传入两个参数(可以只传其一):
-
要注入的属性的名称;
-
注入属性不存在时的默认值;
const name = inject("name")
const age = inject("age", 0)
对于复杂数据的传共享,都会使用
Vuex
或者pinia
去共享数据。大部分情况不会去使用依赖注入的方式
六、setup语法糖
6.1 <script setup>
语法的优势
当打算把所有的内容都写在setup
函数中时,可以使用<script setup>
语法。
<script setup>
是在单文件组件 (SFC
) 中使用组合式 API
的编译时语法糖。
当同时使用SFC
与组合式API
时则推荐该语法,他有如下特点:
-
更少的样板内容,更简洁的代码
-
能够使用纯
Typescript
声明prop
和抛出事件 -
更好的运行时性能
-
更好的
IDE
类型推断性能
6.2 基础语法示例
<template>
<div>AppContent: {{ message }}</div>
<button @click="changeMessage">修改message</button>
<show-info name="why"
:age="18"
@info-btn-click="infoBtnClick"
ref="showInfoRef">
</show-info>
<show-info></show-info>
<show-info></show-info>
</template>
<script setup>
// 1.所有编写在顶层中的代码, 都是默认暴露给template可以使用
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
// 2.定义响应式数据
const message = ref("Hello World")
console.log(message.value)
// 3.定义绑定的函数
function changeMessage() {
message.value = "你好啊, 李银河!"
}
function infoBtnClick(payload) {
console.log("监听到showInfo内部的点击:", payload)
}
// 4.获取组件实例
const showInfoRef = ref()
onMounted(() => {
showInfoRef.value.foo()
})
</script>
注意点:
-
如何使用?
将
setup
属性 添加到<script>
标签上。里面的代码会被编译成组件setup()
函数的内容。这意味着与普通的
6.3 如何定义props的值
使用setup
语法糖时,提供了defineProps()
函数去定义props
。
<template>
<div>ShowInfo: {{ name }}-{{ age }}</div>
</template>
<script setup>
// 定义props
const props = defineProps({
name: {
type: String,
default: "默认值"
},
age: {
type: Number,
default: 0
}
})
</script>
defineProps()
函数的返回值是一个只读属性,只能使用,不能修改。
6.4 如何发出事件
使用setup
语法糖时,提供了defineEmits()
函数去发出事件,从而给父元素传递一些信息。
<template>
<button @click="showInfoBtnClick">showInfoButton</button>
</template>
<script setup>
// 绑定函数, 并且发出事件
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
emits("infoBtnClick", "showInfo内部发生了点击")
}
</script>
6.4 如何暴露方法或者属性
使用<script setup>
的组件内容是不公开的。
意思就是在父组件中的模板ref
或者$parent
链获取到的组件的公开实例。
不会暴露任何在<script setup>
中声明的属性或者方法。
通过defineExpose
编译器宏来显式指定在<script setup>
组件中要暴露出去的属性或者方法。
子组件:
<template>
<div></div>
</template>
<script setup>
// 定义foo的函数
function foo() {
console.log("foo function")
}
// 把foo函数暴露出去
defineExpose({
foo
})
</script>
父组件:
<template>
<show-info ref="showInfoRef"></show-info>
</template>
<script setup>
// 导入内置函数和ShowInfo组件
import { ref, onMounted } from 'vue'
import ShowInfo from './ShowInfo.vue'
// 获取组件实例(只能使用组件中暴露出来的属性和方法)
const showInfoRef = ref()
onMounted(() => {
showInfoRef.value.foo()
})
</script>
更多推荐
所有评论(0)