一.watch监视
情况一
监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。
// 监视,情况一:监视【ref】定义的【基本类型】数据
const stopWatch = watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
if(newValue >= 10){
stopWatch()
}
})
情况二
监视ref定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
注意:
若修改的是ref定义的对象中的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象。
若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。
/*
监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
watch的第一个参数是:被监视的数据
watch的第二个参数是:监视的回调
watch的第三个参数是:配置对象(deep、immediate等等.....)
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{deep:true,immediate:true})
情况三
监视reactive定义的【对象类型】数据,且默认开启了深度监视,且深层监视无法关闭。
无法监视地址值,因为对象地址值没有改变,本质上assign在原对象上进行的是赋值。
newValue和oldValue值相同,都是新值,还是因为对象地址值没有改变,本质上assign在原对象上进行的是赋值。
// 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
})
情况四
监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:
- 若该属性值不是【对象类型】即【基本类型】,需要写成函数形式,此时oldValue是旧值,newValue是新值。
- 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
// 监视,情况四:监视响应式对象中的某个属性,且该属性是【基本类型】的,要写成函数式
/* watch(()=> person.name,(newValue,oldValue)=>{
console.log('person.name变化了',newValue,oldValue)
}) */
// 监视,情况四:监视响应式对象中的某个属性,且该属性是【对象类型】的,可以直接写,也能写函数,更推荐写函数
//直接写:
watch(person.car, (newValue, oldValue) => {
console.log('person.car变化了', newValue, oldValue)
}, { deep: true })
//写函数(不开启深度监视):
watch(()=>person.car,(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
})
//写函数(开启深度监视):
watch(()=>person.car,(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
情况五
监视上述的多个数据
// 监视,情况五:监视上述的多个数据
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
二.watchEffect
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。
watch对比watchEffect
- 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
- watch:要明确指出监视的数据
- watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。
<template>
<div class="person">
<h1>需求:水温达到50℃,或水位达到20cm,则联系服务器</h1>
<h2 id="demo">水温:{{temp}}</h2>
<h2>水位:{{height}}</h2>
<button @click="changePrice">水温+1</button>
<button @click="changeSum">水位+10</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch,watchEffect} from 'vue'
// 数据
let temp = ref(0)
let height = ref(0)
// 方法
function changePrice(){
temp.value += 10
}
function changeSum(){
height.value += 1
}
// 用watch实现,需要明确的指出要监视:temp、height
watch([temp,height],(value)=>{
// 从value中获取最新的temp值、height值
const [newTemp,newHeight] = value
// 室温达到50℃,或水位达到20cm,立刻联系服务器
if(newTemp >= 50 || newHeight >= 20){
console.log('联系服务器')
}
})
// 用watchEffect实现,不用
const stopWtach = watchEffect(()=>{
// 室温达到50℃,或水位达到20cm,立刻联系服务器
if(temp.value >= 50 || height.value >= 20){
console.log(document.getElementById('demo')?.innerText)
console.log('联系服务器')
}
// 水温达到100,或水位达到50,取消监视
if(temp.value === 100 || height.value === 50){
console.log('清理了')
stopWtach()
}
})
</script>
三.标签的ref属性
用在普通DOM标签上,获取的是DOM节点。
用在组件标签上,获取的是组件实例对象。
用在DOM标签上,获取dom节点比id方便
<template>
<div class="person">
<h1 ref="title1">尚硅谷</h1>
<h2 ref="title2">前端</h2>
<h3 ref="title3">Vue</h3>
<input type="text" ref="inpt"> <br><br>
<button @click="showLog">点我打印内容</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref} from 'vue'
let title1 = ref()
let title2 = ref()
let title3 = ref()
function showLog(){
// 通过id获取元素
//const t1 = document.getElementById('title1')
// 打印内容
//console.log((t1 as HTMLElement).innerText)
//console.log((<HTMLElement>t1).innerText)
//console.log(t1?.innerText)
/**********************************************/
// 通过ref获取元素
console.log(title1.value)
console.log(title2.value)
console.log(title3.value)
}
</script>
用在组件上,获取的是组件的实例对象
需要使用defineExpose将子组件的数据导出交给外部
<!-- 父组件App.vue -->
<template>
<Person ref="ren"/>
<button @click="test">测试</button>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {ref} from 'vue'
let ren = ref()
function test(){
console.log(ren.value.name)
console.log(ren.value.age)
}
</script>
<!-- 子组件Person.vue中要使用defineExpose暴露内容 -->
<script lang="ts" setup name="Person">
import {ref,defineExpose} from 'vue'
// 数据
let name = ref('张三')
let age = ref(18)
/****************************/
/****************************/
// 使用defineExpose将组件中的数据导出交给外部
defineExpose({name,age})
</script>
四.props
props用于父子组件的传值,接收外面传过来的数据,使用频率较高
defineProps接收的值以数组的形式表示
ts限制类型
// 定义一个接口,限制每个Person对象的格式
export interface PersonInter {
id:string,
name:string,
age:number
}
// 定义一个自定义类型Persons
export type Persons = Array<PersonInter>
父组件
<template>
//peson组件接收名为list的prop
<Person :list="persons"/>
</template>
<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>
<div class="person">
<ul>
<li v-for="item in list" :key="item.id">
{{item.name}}--{{item.age}}
</li>
</ul>
</div>
</template>
<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
import {type PersonInter} from '@/types'
// 第一种写法:仅接收
// const props = defineProps(['list'])
// 第二种写法:接收+限制类型
// defineProps<{list:Persons}>()
// 第三种写法:接收+限制类型+指定默认值+限制必要性
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'asdasg01',name:'小猪佩奇',age:18}]
})
console.log(props)
</script>
五.vue3的生命周期
有六个钩子
创建阶段:setup
挂载阶段:onBeforeMount、onMounted
更新阶段:onBeforeUpdate、onUpdated
卸载阶段:onBeforeUnmount、onUnmounted
用法
<template>
<div class="person">
<h2>当前求和为:{{ sum }}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<!-- vue3写法 -->
<script lang="ts" setup name="Person">
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// 数据
let sum = ref(0)
// 方法
function changeSum() {
sum.value += 1
}
console.log('setup')
// 生命周期钩子
onBeforeMount(()=>{
console.log('挂载之前')
})
onMounted(()=>{
console.log('挂载完毕')
})
onBeforeUpdate(()=>{
console.log('更新之前')
})
onUpdated(()=>{
console.log('更新完毕')
})
onBeforeUnmount(()=>{
console.log('卸载之前')
})
onUnmounted(()=>{
console.log('卸载完毕')
})
</script>
六.自定义hook
自定义 hook 是一种封装可重用逻辑的有效方式。自定义 hook 本质上是一个普通的 JavaScript 函数,它可以使用 Vue 3 的 Composition API(如 ref, reactive, computed, watch, onMounted, onUnmounted 等)来创建响应式的状态和其他功能。
使用:
1.定义自定义 hook: 通常,自定义 hook 的名称会以 use 开头,以便清楚地表明它是一个 hook 函数。
2.使用 Composition API: 在 hook 函数内部,您可以使用 Composition API 来创建响应式的状态或执行副作用等。
3.返回有用的值: 您可以从 hook 函数中返回响应式数据、方法或其他工具函数,以便在组件中使用。
1.创建
在ts里面创建
useSum.ts
import { ref ,onMounted,computed} from 'vue'
export default function () {
// 数据
let sum = ref(0)
let bigSum = computed(()=>{
return sum.value * 10
})
// 方法
function add() {
sum.value += 1
}
// 钩子
onMounted(()=>{
add()
})
// 给外部提供东西
return {sum,add,bigSum}
}
2.使用
<template>
<div class="person">
<h2>当前求和为:{{ sum }},放大10倍后:{{ bigSum }}</h2>
<button @click="add">点我sum+1</button>
<hr>
<img v-for="(dog,index) in dogList" :src="dog" :key="index">
<br>
<button @click="getDog">再来一只小狗</button>
</div>
</template>
<script lang="ts" setup name="Person">
import useSum from '@/hooks/useSum'
import useDog from '@/hooks/useDog'
const {sum,add,bigSum} = useSum()
const {dogList,getDog} = useDog()
</script>