前言:上一篇computed没讲但是用到了,所以这篇仔细讲解一些computed和监听,监听分为:手动监听和自动监听,手动监听又分为...往下看

Vue3进阶指南:从零到精通
Vue3作为前端开发的热门框架,其强大的功能和灵活的API让无数开发者为之着迷。今天,我们就来深入探讨Vue3的核心语法进阶知识,帮助大家从零开始,逐步掌握Vue3的精髓。
一、计算属性:computed
1.1 计算属性的基本概念
计算属性(computed
)是Vue3中一个非常强大的功能,它可以根据已有的数据计算出新的数据。计算属性的作用和Vue2中的computed
一致,但它在Vue3中有了更灵活的使用方式。
1.2 只读计算属性
只读计算属性是指只能读取,不能修改的属性。例如,我们有一个firstName
和lastName
,我们可以通过计算属性生成一个fullName
:
html
<template>
<div>
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{ fullName }}</span>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed(() => `${firstName.value}-${lastName.value}`)
</script>
在这个例子中,fullName
是一个只读计算属性,它会根据firstName
和lastName
的变化自动更新。
1.3 可读写计算属性
除了只读计算属性,我们还可以定义可读写的计算属性。这意味着我们不仅可以读取它的值,还可以修改它的值。例如:
html
<template>
<div>
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{ fullName }}</span>
<button @click="changeFullName">全名改为:李四</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed({
get() {
return `${firstName.value}-${lastName.value}`
},
set(val) {
const [newFirstName, newLastName] = val.split('-')
firstName.value = newFirstName
lastName.value = newLastName
}
})
function changeFullName() {
fullName.value = '李-四'
}
</script>
在这个例子中,我们可以通过点击按钮修改fullName
的值,同时firstName
和lastName
也会相应地更新。
二、监听器:watch
2.1 监听器的基本概念
watch
是Vue3中用来监视数据变化的工具。它可以监视ref
、reactive
定义的数据,以及函数返回的值。当监视的数据发生变化时,watch
会触发一个回调函数。
2.2 监听ref
定义的数据
2.2.1 监听基本类型数据
我们可以直接监视ref
定义的基本类型数据。例如:
html
<template>
<div>
当前求和为:{{ sum }}
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const sum = ref(0)
function changeSum() {
sum.value += 1
}
watch(sum, (newValue, oldValue) => {
console.log(`sum从${oldValue}变为了${newValue}`)
})
</script>
在这个例子中,当sum
的值发生变化时,watch
会触发回调函数,并打印出新旧值。
2.2.2 监听对象类型数据
如果ref
定义的是一个对象类型数据,我们需要注意监视的是对象的地址值。如果需要监视对象内部的数据,需要手动开启深度监视。例如:
html
<template>
<div>
姓名:{{ person.name }}<br>
年龄:{{ person.age }}<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const person = ref({ name: '张三', age: 18 })
function changeName() {
person.value.name += '~'
}
function changeAge() {
person.value.age += 1
}
function changePerson() {
person.value = { name: '李四', age: 90 }
}
watch(person, (newValue, oldValue) => {
console.log(`person从${oldValue}变为了${newValue}`)
}, { deep: true }) // 开启深度监视
</script>
在这个例子中,我们开启了深度监视,因此当person
对象内部的属性发生变化时,watch
也会触发回调函数。
2.3 监听reactive
定义的数据
reactive
定义的对象类型数据默认开启了深度监视。例如:
html
<template>
<div>
姓名:{{ person.name }}<br>
年龄:{{ person.age }}<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const person = reactive({ name: '张三', age: 18 })
function changeName() {
person.name += '~'
}
function changeAge() {
person.age += 1
}
function changePerson() {
person = { name: '李四', age: 90 }
}
watch(person, (newValue, oldValue) => {
console.log(`person从${oldValue}变为了${newValue}`)
})
</script>
在这个例子中,reactive
定义的person
对象默认开启了深度监视,因此当person
对象内部的属性发生变化时,watch
会触发回调函数。
2.4 监听对象中的某个属性
我们可以监视ref
或reactive
定义的对象类型数据中的某个属性。如果该属性是基本类型,需要写成函数形式;如果该属性是对象类型,可以直接写,也可以写成函数形式,但更推荐写成函数形式。例如:
html
<template>
<div>
姓名:{{ person.name }}<br>
年龄:{{ person.age }}<br>
汽车:{{ person.car.c1 }}、{{ person.car.c2 }}<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一台车</button>
<button @click="changeC2">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const person = reactive({
name: '张三',
age: 18,
car: { c1: '奔驰', c2: '宝马' }
})
function changeName() {
person.name += '~'
}
function changeAge() {
person.age += 1
}
function changeC1() {
person.car.c1 = '奥迪'
}
function changeC2() {
person.car.c2 = '大众'
}
function changeCar() {
person.car = { c1: '雅迪', c2: '爱玛' }
}
watch(() => person.name, (newValue, oldValue) => {
console.log(`person.name从${oldValue}变为了${newValue}`)
})
watch(() => person.car, (newValue, oldValue) => {
console.log(`person.car从${oldValue}变为了${newValue}`)
}, { deep: true })
</script>
在这个例子中,我们通过函数形式监视了person.name
和person.car
的变化。
2.5 监听多个数据
我们还可以同时监视多个数据。例如:
html
<template>
<div>
姓名:{{ person.name }}<br>
年龄:{{ person.age }}<br>
汽车:{{ person.car.c1 }}、{{ person.car.c2 }}<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一台车</button>
<button @click="changeC2">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
const person = reactive({
name: '张三',
age: 18,
car: { c1: '奔驰', c2: '宝马' }
})
function changeName() {
person.name += '~'
}
function changeAge() {
person.age += 1
}
function changeC1() {
person.car.c1 = '奥迪'
}
function changeC2() {
person.car.c2 = '大众'
}
function changeCar() {
person.car = { c1: '雅迪', c2: '爱玛' }
}
watch([() => person.name, person.car], (newValue, oldValue) => {
console.log(`person.name从${oldValue[0]}变为了${newValue[0]}`)
console.log(`person.car从${oldValue[1]}变为了${newValue[1]}`)
}, { deep: true })
</script>
在这个例子中,我们同时监视了person.name
和person.car
的变化。
三、自动监听:watchEffect
watchEffect
是Vue3中一个非常强大的功能,它可以让一个函数自动响应式地追踪其依赖,并在依赖更改时重新执行该函数。
3.1 watch
vs watchEffect
-
watch
需要明确指出监视的数据。 -
watchEffect
不需要明确指出监视的数据,它会自动追踪函数中用到的响应式数据。
3.2 使用示例
例如,我们有一个需求:当水温达到50℃或水位达到20cm时,联系服务器。我们可以使用watch
或watchEffect
来实现:
html
<template>
<div>
水温:{{ temp }}<br>
水位:{{ height }}<br>
<button @click="changeTemp">水温+10</button>
<button @click="changeHeight">水位+1</button>
</div>
</template>
<script setup>
import { ref, watch, watchEffect } from 'vue'
const temp = ref(0)
const height = ref(0)
function changeTemp() {
temp.value += 10
}
function changeHeight() {
height.value += 1
}
// 使用watch实现
watch([temp, height], (value) => {
const [newTemp, newHeight] = value
if (newTemp >= 50 || newHeight >= 20) {
console.log('联系服务器')
}
})
// 使用watchEffect实现
const stopWatch = watchEffect(() => {
if (temp.value >= 50 || height.value >= 20) {
console.log('联系服务器')
}
if (temp.value === 100 || height.value === 50) {
console.log('清理了')
stopWatch()
}
})
</script>
在这个例子中,watchEffect
会自动追踪temp
和height
的变化,并在满足条件时执行回调函数。
特性/对比点 | watch |
watchEffect |
---|---|---|
基本概念 | 监视特定的数据源,在数据变化时执行回调。 | 立即运行一个函数,并响应式追踪其依赖,在依赖更新时重新运行该函数。 |
监听目标指定 | 需要明确指出要监视的数据(可以是单个值、多个值或getter函数)。 | 不需要明确指出监视的数据,自动收集函数内部使用的响应式数据作为依赖。 |
初始化执行 | 不会在初始运行时执行回调,仅在侦听的值发生变化时触发。 | 在组件首次渲染时会立即执行一次,以建立依赖关系。 |
数据依赖追踪 | 只会关注你明确监视的数据。 | 自动追踪函数内使用的所有响应式数据,并且当这些数据改变时重新运行。 |
停止监听的方式 | 可通过返回的停止函数手动停止监听。 | 同样可以通过返回的停止函数来手动停止监听。 |
适用场景示例 | 当你需要监听某个特定数据的变化并做出反应时非常有用,例如监听表单输入值的变化。 | 当你需要基于多个响应式数据进行操作并且希望自动管理这些依赖关系时特别有用。 |
代码复杂度 | 通常需要更多的配置,比如需要明确指定要监听的数据源,可能会导致代码略显冗长。 | 由于能够自动追踪依赖,代码通常更加简洁明了。 |
深度监听设置 | 对于对象类型的数据,默认不会进行深度监听,但可以通过选项开启深度监听。 | 如果依赖中包含的对象发生了任何变化,都会触发重新运行,相当于默认启用了深度监听。 |
好啦computed和监听就到这里拉,接下来是生命周期的讲解拉
