首先是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)

发表评论

邮箱地址不会被公开。 必填项已用*标注