vue3核心语法(二)

一.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定义的【对象类型】数据中的某个属性,注意点如下:

  1. 若该属性值不是【对象类型】即【基本类型】,需要写成函数形式,此时oldValue是旧值,newValue是新值。
  2. 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
 // 监视,情况四:监视响应式对象中的某个属性,且该属性是【基本类型】的,要写成函数式
  /* 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

  1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
  2. watch:要明确指出监视的数据
  3. 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值