首先是Vue3中的一个重要属性,computed
Computed是什么呢,这里简单的说一下,可以理解为一个具有缓存的函数,可以将函数的返回值进行包裹,形成refImpl,当多个地方引用到这个computed的时候,可以进行返回,当computed使用的变量被修改的时候,会自动触发computed进行重新计算。
这里我们声明两个变量
let firstName = ref(‘zhang’)
let lastName = ref(‘san’)
同时我们可以简单的在template之中使用这两个变量
姓:<input type=”text” v-model=”firstName”> <br>
名:<input type=”text” v-model=”lastName”> <br>
之后我们希望有一个全名的变量,当firstname或者lastname进行变化的时候同步展示变化
全名:<span>{{fullName}}</span> <br>
对于这样的一个fullname,我们可以就使用computed来进行实现
let fullName = computed(()=>{
return firstName.value + lastName.value
}
这种使用之后,如果我们在修改firstname或者lastname的时候,fullname会重新计算,并显示在上面。
那么我们希望反着,当修改fullname的时候,可以同步显示在firstname和lastname上
对于这种需求,需要在computed中声明实现 get set 函数
// 计算属性——既读取又修改
let fullName = computed({ // 读取 get(){ return firstName.value + ‘-‘ + lastName.value }, // 修改 set(val){ console.log(‘有人修改了fullName’,val) firstName.value = val.split(‘-‘)[0] lastName.value = val.split(‘-‘)[1] } }) function changeFullName(){ fullName.value = ‘li-si’ } |
除了computed之外,还有一个函数watch,其目的是监控某些变量的变化,当符合变化的时候触发操作
其可以监控如下的四种数据
ref 定义的数据
reactive定义的数据
定义了getter函数的函数
一个包含了上述内容的数组
最简单的watch使用
也就是监控一个被ref包裹的变量的值
这里我们在scirpt之中首先定义一个变量和对应的方法
let sum = ref(0)
// 方法
function changeSum(){
sum.value += 1
}
并在template中声明使用这两者
<template>
<div class=”person”>
<h1>情况一:监视【ref】定义的【基本类型】数据</h1>
<h2>当前求和为:{{sum}}</h2>
<button @click=”changeSum”>点我sum+1</button>
</div>
</template>
这时候我们可以在scirpt之中
定义了一个watch函数进行监控
import {watch} from vue
const stopWatch = watch(sum,(newValue,oldValue)=>{
console.log(‘sum变化了’,newValue,oldValue)
})
这样会在变化的时候传入new和old的值
其次是我们获得的stopWatch这个对象
这个对象其实是watch函数的返回值,是一个停止监控的方法,调用其可以停止对应的监控操作。
上面我们说了利用watch,监控一个ref包裹的基本数据类型的响应式数据,那么如果我们使用ref包裹一个对象类型的响应式数据呢?这时候监视,获取到的是什么呢?
let person = ref({
name:’张三’,
age:18
})
对于这样的ref的代码,如果我们希望进行监控的话,那么我们可以注册函数进行修改
function changeName(){
person.value.name += ‘~’
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value = {name:’李四’,age:90}
}
对于上面三个函数,带来的修改,我们先看下直接注册一个watch的话,哪些变化会触发watch
watch(person,(newValue,oldValue)=>{
console.log(‘person变化了’,newValue,oldValue)
})
直接点击页面触发上面三个函数,会发现,直接修改其中的name和age并不会触发watch,只有最后一个changePerson会触发,这是由于watch监控的是变量的地址,因为前两个并不没有改变变量在内存中的地址。
如果期待监控内部的属性的话,那么可以在watch函数中,声明开启深度监控
watch(person,(newValue,oldValue)=>{
console.log(‘person变化了’,newValue,oldValue)
},{deep:true})
只不过在配置之后还需要注意的是,虽然深度监控可以检测到数值的变化
但是传入的newValue和oldValue都是一样的,这是因为其内存地址未发生改变。
对于reactive定义的对象类型的数据,默认开启了深度监控
let obj = reactive({
a:{
b:{
c:666
}
}
})
watch(person,(newValue,oldValue)=>{
console.log(‘person变化了’,newValue,oldValue)
})
如果希望监控一个对象中的某个属性
可以写一个函数,进行返回
如果是对象类型,虽然可以直接监控,但是写作为一个函数可以支持深度监控
这里我们以监控内部基本数据类型的属性来进行查看
watch(()=> person.name,(newValue,oldValue)=>{
console.log(‘person.name变化了’,newValue,oldValue)
})
我们利用一个get函数
()=>person,name
获取到这个属性的get函数书写完成之后,就可以监控对应的变化了。
除此之外就是对象类型
我们的形式也是一样
()=>person.car
这个car是一个对象类型的属性
car:{
c1:’奔驰’,
c2:’宝马’
}
不过需要注意,默认情况下监控的是地址的变化,如果希望监视内部的属性变化,那么需要书写开始深度监控
watch(()=>person.car,(newValue,oldValue)=>{
console.log(‘person.car变化了’,newValue,oldValue)
},{deep:true})
最后我们综合起来来看
watch也支持对多个属性进行监控
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log(‘person.car变化了’,newValue,oldValue)
},{deep:true})
需要利用了一个函数进行返回所有需要监控的属性
在说完watch之后,还有一个类似的watchEffect可以进行监控
这个和watch 不一样的是,wacthEffect并不需要手动声明需要监控的对象属性,而是会根据当前内部声明的属性来进行监控。
import {watchEffect} from ‘vue’
书写很简单
const stopWtach = watchEffect(()=>{
// 水温达到100,或水位达到50,取消监视
if(temp.value === 100 || height.value === 50){
console.log(‘清理了’)
stopWtach()
}
})
这样当temp作为一个ref响应式数据变化的时候,就会触发这个监控,我们还利用了if,
从而判断条件是否达到了临界值。从而触发不同的操作。
在本章的最后,我们说下如何进行简单的跨组件通信,本次只涉及到父传子
不过首先先说下如何定义一个接口,或者说定义一个结构模板
我们直接声明一个ts文件,
export interface PersonaInter {
id:string,
name:string,
age:number
}
接下来我们在定义结构体的时候,只需要在结构体后面声明其的接口限制即可。
import {type PersonInter} from ‘@/types’
let person:Person = {id:”123456”,name:”zhangsan”,age:60}
在了解了interface用于定义结构体模板之后
那么我们可以看下在不同层次的文件中,如何传递我们的结构体
如果我们在父vue中声明了变量,那么我们可以在template中声明引入子Vue的时候传递变量给子类。
<script lang=”ts” setup name=”App”>
import Person from ‘./components/Person.vue’ import {reactive} from ‘vue’ import {type Persons} from ‘./types’ let persons = reactive<Persons>([ {id:’e98219e12′,name:’张三’,age:18}, {id:’e98219e13′,name:’李四’,age:19}, {id:’e98219e14′,name:’王五’,age:20} ]) </script> |
这样在template中,当我们引入子Vue的时候,传递这个参数给其
<template>
<Person :list=”persons”/>
</template>
而在子Vue中获取这样一个对象
这里我们需要用到一个内置函数
defineProps
其可以接受来自父Vue传入的参数
const props = defineProps([‘list’])
然后我们就可以在上方template之中声明使用对象了
<ul>
<li v-for=”item in list” :key=”item.id”>
{{item.name}}–{{item.age}}
</li>
</ul>
对于defineProps
来有着更多的用法
比如可以传入泛型来进行类型的控制
defineProps<{list:Persons}>()
或者是限制类型的同时还可以增加默认值
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:’asdasg01′,name:’小猪佩奇’,age:18}]
})
这样即使父Vue不传递值的话,子Vue之中也可以进行编译使用。
最后,Vue3还提供了一些有趣的标签属性供我们使用。
比如ref 属性
可以帮助我们获取DOM节点或者组件实例对象。
比如我们在template之中定义的DOM组件中声明了ref
<h2 ref=”title1″>前端</h2>
那么我们在下方script之中,就可以进行配置获取这个节点信息
import {ref} from ‘vue’
let title1 = ref()
之后我们可以在某些函数中使用这个节点
console.log(title1)