vue3核心语法

发布于:2025-07-25 ⋅ 阅读:(15) ⋅ 点赞:(0)


前言

  • setup、ref、reactive、toRefs、computed、watch、props、watchEffect、hooks。

一、setup

1.定义

  • 组合式API核心函数。它是组件逻辑的入口点,替代了vue2中的data,methods等分散的选项式API。

2.作用

  • 在组件中可以写在script标签里面表示逻辑入口,自动返回值。

关键问题1:在setup中能否读到以前data选项或methods选项里面的数据?
不能,浅显的理解一下就是。因为setup没有维护this对象,无法调用。
关键问题2:在data选项或methods选项中可以读到setup中的数据?
可以,需要使用this进行调用。

setup示例:

export default {
    name:'Person', // 组件名
    // 1.setup能和methods data共存 
    // 2.data里面能不能读到setup里面的数据?
    // >>可以,使用this.变量进行读取
    // 3.但是setup不可以读到data里面的数据
    // 4.setup是一个全新的配置项 它的优先级比vue2中的beforeCreate的优先级更高
    // 5.它不存在this,没有维护this对象
    setup(){
        // 1.数据 ---> data选项
        let name = '张三'
        let age = 18
        let tel = '1388888888'
        // 2.方法
        function changeName () {
            // 注意:此时的数据不是响应式的
            // 虽然改了但是页面不会有变化 
            name = 'zhang-san'
        }
        function changeAge () {
            age += 1
        }
        function showTel () {
            alert(tel)
        }
        // 2.通过返回值进行返回数据 可交可不交
        return {
            name,age,
            changeName,changeAge,showTel
        }
        // return ()=>'哈哈' 直接返回 setup的返回值也可以是个渲染函数
    }
}

语法糖:

  • 可以直接写在script标签里,自动返回变量以上的写法等价于下面的写法

关键问题3:如果说需要自定义命名组件名需要单独设置,但是默认是与文件名一致。
关键问题4:如果说要想基本数据类型是响应式的,需要导入ref,将响应式数据用ref()框起来,需要在改变的时候使用.value进行修改。因为在标签里的变量返回值是一个RefImpl实例对象,也就是返回的数据用对象封装起来了,里面的数据就需要.value来进行调用。

<!-- 需要单独设置组件名的话可以在这里设置 就不使用插件了 -->
<script lang="ts">
export default {
    name:'Person123', // 组件名
}
</script>

<script lang="ts" setup>
import {ref} from 'vue'
        let name = ref('张三')
        let age = ref(18)
        let tel = '1388888888'
        function changeName () {
            name.value = 'zhang-san'
        }
        function changeAge () {
            age.value += 1
        }
        function showTel () {
            alert(tel)
        }
</script>

3.响应式数据

1.ref

  • ref是一个响应式的API,用于创建一个响应式的引用,通常用于响应式基本数据类型,也可以用于对象类型的响应
  • 使用的时候将需要响应式的数据导入ref,然后用ref()包裹起来,然后在需要进行修改的时候调用数据.value进行修改。以上示例已经展示了ref的基本数据类型响应。
  • 返回的是一个Proxy代理对象。

ref对象类型响应:

<template>
  <div class="car">
    <h2>品牌:{{ car.brand }}</h2>
    <h2>价格:{{ car.price }}</h2>
    <ul>
        <li v-for="c in cars" :key="c.name">车名:{{ c.name }},价格:{{ c.price }}</li>
    </ul>
    <button @click="changePrice">修改价格</button>
  </div>
</template>

<script lang="ts">
export default {
    name:'Car', 
}
</script>

<script lang="ts" setup>
    // 1.导入ref
    import {ref} from 'vue'
    // 2.用ref包裹起来
    let car = ref({
        brand:'保时捷',
        price:100,
    })
    // 对象数组
    let cars = ref([
        {name:'奔驰',price:100},
        {name:'法拉利',price:1000},
    ])
    // 3.直接修改
    function changePrice() {
        car.value.price += 10 
    }
    console.log(car)
</script>

<style scoped>
    .car {
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
    .button {
        margin: 0 5px;
    }
</style>
  • 它的外层使用ref包裹起来的,内部是reactive处理的。需要先用value读到对象后再进行操作才可以,包括ref里面包含了数组对象,需要用value去读到数组对象后在进行索引等其他操作。
<template>
  <div class="car">
    <h2>品牌:{{ car.brand }}</h2>
    <h2>价格:{{ car.price }}</h2>
    <ul>
        <li v-for="c in cars" :key="c.name">车名:{{ c.name }},价格:{{ c.price }}</li>
    </ul>
    <button @click="changePrice">修改价格</button>
  </div>
</template>

<script lang="ts">
export default {
    name:'Car', 
}
</script>

<script lang="ts" setup>
    // 1.导入reactive
    import {ref} from 'vue'
    // 2.用ref包裹起来
    let car = ref({
        brand:'保时捷',
        price:100,
    })
    // 对象数组
    let cars = ref([
        {name:'奔驰',price:100},
        {name:'法拉利',price:1000},
    ])
    // 3.直接修改
    function changePrice() {
        car.value.price += 10 
    }
    console.log(car)
</script>

<style scoped>
    .car {
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
    .button {
        margin: 0 5px;
    }
</style>

2.reactive

  • reactive也是响应式API,只能用于创建一个响应式对象。
  • 使用的时候需要导入reactive,然后用reactive包裹起来,然后直接修改即可。
    返回的也是一个Proxy代理对象。
    注意不用.value。

reactive响应对象类型:

<template>
  <div class="car">
    <h2>品牌:{{ car.brand }}</h2>
    <h2>价格:{{ car.price }}</h2>
    <button @click="changePrice">修改价格</button>
  </div>
</template>

<script lang="ts" setup>
    // 1.导入reactive
    import {reactive} from 'vue'
    // 2.用reactive包裹起来
    let car = reactive({
        brand:'保时捷',
        price:100,
    })
    // 3.直接修改
    function changePrice() {
    	// 4.不用加.value了
        car.price += 10
    }
</script>

<style scoped>
    .car {
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
    .button {
        margin: 0 5px;
    }
</style>

3.ref与reactive的区别

区别1:ref用来生成响应式数据的时候,需要用.value来访问。
区别2:ref能够修饰基本类型、对象类型的响应式数据。
总结:基本类型用ref,层级不深的对象使用ref。
总结:层级深的使用reactive。

4.toRefs

作用:能够将reactive包裹的对象响应式数据解构,能够将它的每一个字段变成ref对象。
实质:将某个对象的字段结构,将该字段与对象里的字段变成一摸一样的数据,意思是调用toRefs后我们可以修改对象的字段了。

<template>
    <div class="person">
        <h2>{{ name }}</h2>
        <h2>{{ age }}</h2>
        <button @click="changeAge">修改年龄</button>
        <button @click="changeName">修改名字</button>
    </div>
</template>

<script lang="ts">
export default {
    name:'ToRefs',
}
</script>

<script lang=ts setup>
    import {ref,reactive,toRefs} from 'vue'
    let person = reactive({
        name:"kkk",
        age:999,
    })
    let {name, age} = toRefs(person)

    function changeName() {
        name.value = name.value + "k"
    }

    function changeAge() {
        age.value += 1
    }
</script>

<style scoped>
    .person {
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
    .button {
        margin: 0 5px;
    }
</style>

5.computed

定义:计算属性,基于响应式数据计算响应值。
使用:需要get和set方法。像jv里的getter和setter。
v-model:数据双向绑定。
const:明确声明不可变数据。
const [str1,str2] = val.split(‘’-‘’) :数组也能解构定义。

<template>
    <div class="person">
       姓:<input type="text" v-model="firstName"> <br>
       名:<input type="text" v-model="lastName"> <br>
       <!-- v-model 是 Vue 提供的双向数据绑定指令,主要用于 <input><select><textarea> 等表单元素,实现数据与视图的自动同步。 -->
       全名:<span>{{ fullname }}</span> <br>
       修改:<button @click="changeFullName"></button>
    </div>
</template>

<script lang="ts">
export default {
    name:"Compute",
}
</script>

<script setup lang="ts">
    import {ref,reactive, computed} from 'vue'
    let firstName = ref("jo")
    let lastName = ref("ny")
    // 变成一个可读可写的计算属性
    let fullname = computed({
        get(){
            return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + "-" + lastName.value
        },
        set(val){
        // 数组也能解构赋值
            const [str1,str2] = val.split("-")
            firstName.value = str1
            lastName.value = str2
        }
    })

    function changeFullName() {
        fullname.value = "gy-ro"
    }
</script>

<style scoped>
    .person {
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
    .button {
        margin: 0 5px;
    }
</style>

二、Watch

  • 它能够监视数据.。

注意1:需要监视的值不需要加.value,因为自动解包。
注意2:调用watch返回值是一个监视停止器,再次调用就会停止监视。
注意3:它只监视4种数据。函数返回值,ref、reactive和它们的数组。

1.监视ref:基本数据

<template>
    <div class="person">
        <h1>监视数据</h1>
        <h1>当前数据求和为:{{ sum }}</h1>
        <button @click="changeSum"></button>
    </div>
</template>

<script lang="ts">
export default { // 实际上这里要缩进这个大括号一下才不会报错
    name:"Watch",
}
</script>
<script lang="ts" setup>
import {ref, watch} from 'vue'
// 需要用ref或reactive包裹起来
    let sum = ref(0)
    function changeSum(){
        sum.value += 1
    }
    // 监视
    const stopWatch = watch(sum, (nv,ov)=>{
        console.log("sum变化了", nv, ov)
        if(nv >= 10) {
            stopWatch() // 如果newValue大于等于10就停止监视 stopWatch()表示停止监视
        }
    })
</script>

2.监视ref:对象数据

  • 监视用ref包裹的对象数据需要手动开启深度监视。
  • 监视的是地址,整个对象,只有整个对象改变的时候才会触发监视器。
  • 如果想要深度监视,需要手动添加深度监视。
  • {immediate:true}:添加在深度监视后面。表示不管你改没改,先执行一次箭头函数。它提醒的是旧的引用,如果没改变,那就还是新的那个对象,已经改了。
  • 实际上开发不管旧值。

参数1:被监视的数据。
参数2:监视的回调函数。
参数3:配置对象。
实质:改的是它的引用。

<template>
    <div class="person">
      <h1>情况二:监视【ref】定义的【对象类型】数据</h1>
      <h2>姓名:{{ person.name }}</h2>
      <h2>年龄:{{ person.age }}</h2>
      <button @click="changeName">修改名字</button>
      <button @click="changeAge">修改年龄</button>
      <button @click="changePerson">修改整个人</button>
    </div>
  </template>
  
<script lang="ts">
export default {
    name:"Watch2",
}

</script>
  <script lang="ts" setup>
    import {ref,watch} from 'vue'
    // 数据
    let person = ref({
      name:'张三',
      age:18,
    })
    // 方法
    function changeName(){
      person.value.name += '~'
    }
    function changeAge(){
      person.value.age += 1
    }
    function changePerson(){
      person.value = {name:'李四', age:90}
    }
    /* 
      监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
      watch的第一个参数是:被监视的数据
      watch的第二个参数是:监视的回调
      watch的第三个参数是:配置对象(deep、immediate等等.....) 
    */
    watch(person,(nv,ov)=>{
      console.log('person变化了',nv,ov)
    }, {deep:true})
    
  </script>

3.监视reactive:对象数据。

  • 默认开启深度监视。且关不掉哦。

修改对象: Object.assign(person,{name:‘李四’,age:80})。
第一个参数是要改的对象,第二个参数是要改的内容。
实质:没改变原引用,只覆盖了值。

<template>
    <div class="person">
      <h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
      <h2>姓名:{{ person.name }}</h2>
      <h2>年龄:{{ person.age }}</h2>
      <button @click="changeName">修改名字</button>
      <button @click="changeAge">修改年龄</button>
      <button @click="changePerson">修改整个人</button>
      <hr>
      <h2>测试:{{obj.a.b.c}}</h2>
      <button @click="test">修改obj.a.b.c</button>
    </div>
  </template>
  
  <script lang="ts" setup name="Person">
    import {reactive,watch} from 'vue'
    // 数据
    let person = reactive({
      name:'张三',
      age:18
    })
    let obj = reactive({
      a:{
        b:{
          c:666
        }
      }
    })
    // 方法
    function changeName(){
      person.name += '~'
    }
    function changeAge(){
      person.age += 1
    }
    function changePerson(){
      Object.assign(person,{name:'李四',age:80})
    }
    function test(){
      obj.a.b.c = 888
    }
  
    // 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
    watch(person,(nv,ov)=>{
      console.log('person变化了',nv,ov)
    })
    watch(obj,(nv,ov)=>{
      console.log('Obj变化了',nv,ov)
    })
  </script>

4.监视ref或reactive中某个属性

  • 当我们直接修改的时候直接把原对象的地址改了,在watch传入的第一个参数传递的时候就要看地址到底是谁的,可能是原对象的可能是已经改了的。
  • 总之一句话,如果我们只想监听对象的其中某个属性,将他写成箭头函数形式,并开启深度监听,记住就行。
<template>
  <div class="person">
    <h1>情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h1>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>汽车:{{ person.car.c1 }}{{ person.car.c2 }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeC1">修改第一台车</button>
    <button @click="changeC2">修改第二台车</button>
    <button @click="changeCar">修改整个车</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import {reactive,watch} from 'vue'

  // 数据
  let 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变化了',newValue,oldValue)
  }) */

  // 监视,情况四:监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
  watch(()=>person.car,(newValue,oldValue)=>{
    console.log('person.car变化了',newValue,oldValue)
  },{deep:true})
</script>

5.监视多个属性

  • 多个属性放数组里,说白了如果是单纯的监听某一个属性,写成箭头函数形式,如果监听某一个对象,那就直接写就行了。
<template>
  <div class="person">
    <h1>情况五:监视上述的多个数据</h1>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>汽车:{{ person.car.c1 }}{{ person.car.c2 }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeC1">修改第一台车</button>
    <button @click="changeC2">修改第二台车</button>
    <button @click="changeCar">修改整个车</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import {reactive,watch} from 'vue'

  // 数据
  let 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.car变化了',newValue,oldValue)
  },{deep:true})

</script>

6.watchEffect

  • watch需要明确指出要监视的数据。
  • watchEffect不需要,在箭头函数里用到了什么就自动注入什么。
  • 相对于性能来说,watch会更好。
<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">
export default {
    name : "WatchEffect",
}
</script>

<script lang="ts" setup>
  import {ref,watch,watchEffect} from 'vue'
  // 数据
  let temp = ref(0)
  let height = ref(0)

  // 方法
  function changePrice(){
    temp.value += 10
  }
  function changeSum(){
    height.value += 1
  }
  // 方法1:通过watch
  const stopWatch_1 = watch([temp, height], (v)=>{
    const [newTemp, newHeight] = v
    if(newTemp >= 50 || newHeight >= 20) {
        console.log("正在发出警告...")
        stopWatch_1()
    }
  })
  // 方法2:通过watchEffect
  const stopWatch_2 = watchEffect(()=>{
    if(temp.value >= 50 || height.value >= 50){
        console.log("正在联系服务器...")
    }
    if(temp.value === 100 || height.value === 50) {
        stopWatch_2()
    }
  })
</script>

三、标签中的ref属性

  • 这个属性是vue的特有的,用来动态获取DOM的响应式API,能够方便获取DOM,从而进行一系列操作。

1.DOM节点

  • 通过vue的组合式响应API来获得ref的属性。
  • 就是通过ref()来一一对应。
  • 获得后就可以当作普通的DOM来操作了。
<template>
  <div class="person">
    <h1 ref="title1" id="title1">通过vue获得DOM节点</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>
  import {ref} from 'vue'
	
  let title1 = ref() // 对应title1
  let title2 = ref() // 对应title2
  let title3 = ref() // 对应title3

  function showLog(){
    // 1.传统的DOM操作获取ref属性的DOM节点
    // 通过id获取元素
    const t1 = document.getElementById('title1')
	// 2.通过vue的ref响应式获得ref属性节点
    // 通过ref获取元素
    console.log(title1.value)
    console.log(title2.value)
    console.log(title3.value)
    // 获得后就可以当作普通的DOM来操作
    console.log(t1?.textContent)
    console.log(title1.value?.textContent)
  }
</script>

2.组件标签

步骤1:子组件需要上传数据。
步骤2:其他组件可以通过ref读取并访问。

App.vue

<template>
    <!-- 写html结构 -->
     <!-- 允许多标签 vue2不允许 -->
     <RefAtrributeComps ref="ren"/>
     <button @click="test">点一下</button>
</template>

<script lang="ts" setup>
    import RefAtrributeComps from './components/RefAtrribute-comps.vue';
    import {ref} from 'vue'
    let ren = ref() // 获得了这个组件 拿到这个组件后就可以访问里面组件上传的数据了
    function test() {
        console.log(ren.value.name)
        console.log(ren.value.age)
        console.log(ren.value.name.textContent)
        console.log(ren.value.age.textContent)
    }
</script>
<style>
/* 写样式 */
</style>

RefAttribute-comps

<template>
    <div class="person">
        <h1 ref="name">乔尼</h1>
        <h1 ref="age">19</h1>
    </div>
</template>

<!-- 子组件Person.vue中要使用defineExpose暴露内容 -->
<script lang="ts" setup>
  import {ref,defineExpose} from 'vue'
	// 数据
  let name = ref()
  let age = ref()
  // 要使用defineExpose将组件中的数据交给外部
  defineExpose({name,age})
</script>

3.接口与泛型

  • Java理解:export表示public,定义一个接口interface,里面包含的属性可以作为泛型的属性从而形成规范,再将一个自定义的数组对象Persons传入接口泛型,在其他组件里面就可以直接调用了。
    types文件夹里面的index.ts
// 定义一个接口
export interface IPerson {
    id:string,
    name:string,
    age:number,
}
// 定义一个自定义类型 传入接口泛型
export type Persons = Array<IPerson>

components文件夹里面的Person.vue

<template>
    <div class="Person">

    </div>
</template>

<script lang="ts" setup>

    // @符号表示可以直接无脑引入
    import {type Persons} from '@/types'
    
    let personList:Persons = [
        {id:"1", name:"乔尼", age:19},
        {id:"2", name:"杰洛", age:24}
    ]
</script>

四、props

  • props属性是父组件向子组件传递数据的一种机制,它允许父组件能够向子组件传递数据,使得子组件能够接收并使用这些数据,但是不能直接修改它们,它是单向数据流。

1.父组件

<template>
	<Person :list="persons"/>
	// 向子组件传一个类型为Persons的数组的数据
	// 第一个冒号:表示解引用(c++) 表示不再是普通的字符串
	// js专业术语是数据绑定,表示不再是普通的字符串
</template>

<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {reactive} from 'vue'
import {type Persons} from './types'
// 用reactive包裹是响应式数据
// 指定泛型是这个数组的类型 之前我们已经定义了
 let persons = reactive<Persons>([
  {id:'e98219e12',name:'张三',age:18},
   {id:'e98219e13',name:'李四',age:19},
    {id:'e98219e14',name:'王五',age:20}
  ])
</script>

2.子组件

<template>
<div class="person">
<ul>
// 1.ul和li循环,list是从父组件接收过来的数组
// 2.item表示每一项
// 3.:key表示能够确定每一item的标识
// 4.同理,不是单纯的字符串引用
  <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 Persons} from '@/types/index'

// 第一种写法:仅接收 是defineProps()
// const props = defineProps(['list'])

// 第二种写法:接收+限制类型
// let props = defineProps<{list:Persons}>()

// 第三种写法:接收+限制类型+指定默认值+限制必要性。
// 1.withDedaults表示接收后需要设置默认值。
// 2.defineProps表示从父组件接收数据。
// 3.<{list?:Persons}>表示接收一个list类型,?表示不必要,:Persons表示list中元素的类型,需要提前定义泛型。
// 4.{list:()=>[{id:'asdasg01',name:'乔尼',age:19}]}表示没有接收时的默认值。
// 5.返回的props就是最终子组件接收到的数据。
let props = withDefaults(defineProps<{list?:Persons}>(),{
  list:()=>[{id:'asdasg01',name:'乔尼',age:19}]
})
console.log(props)
</script>

五、组件生命周期

  • 挂载的含义:将vue组件关联到真实的DOM元素上,并完成初始渲染的过程,表示组件从虚拟DOM转换到了实际的页面中了。

  • 生命周期含义:组件从创建、挂载、更新、卸载的整个过程称之为vue组件的生命周期,但是有一些新的钩子,目前还没学到。

  • Vue3的生命周期

    创建阶段:setup

    挂载阶段:onBeforeMountonMounted

    更新阶段:onBeforeUpdateonUpdated

    卸载阶段:onBeforeUnmountonUnmounted

  • 常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)
<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>

六、自定义钩子

  • 很像我们的类。把数据和函数对应为属性和方法。

1.Hooks

  • 与组件包同级。

useDog

import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'

export default function(){
  // 括号里面有个数组括号是初始值是空数组
  let dogList = reactive<string[]>([])

  // 方法
  async function getDog(){
    try {
      // 发请求
      let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      // 维护数据
      dogList.push(result.data.message)
    } catch (error) {
      // 处理错误
      const err = <AxiosError>error
      console.log(err.message)
    }
  }

  // 挂载钩子
  onMounted(()=>{
    getDog()
  })
	
  //向外部暴露数据
  return {dogList,getDog}
}

useSum

import {ref,onMounted} from 'vue'

export default function(){
  let sum = ref(0)

  const increment = ()=>{
    sum.value += 1
  }
  const decrement = ()=>{
    sum.value -= 1
  }
  onMounted(()=>{
    increment()
  })

  //向外部暴露数据
  return {sum,increment,decrement}
}		

2.Components

  • 聚合hooks的组件类。

hooksTest

<template>
  <h2>当前求和为:{{sum}}</h2>
  <button @click="increment">点我+1</button>
  <button @click="decrement">点我-1</button>
  <hr>
  <img v-for="(item,index) in dogList" :key="index" :src="item"> 
  <button @click="getDog">再来一只狗</button>
</template>

<script lang="ts">
  export default {
    name : "HooksTest",
  }
</script>

<script setup lang="ts">
  import useSum from '../../hooks/useSum'
  import useDog from '../../hooks/useDog'
  // 通过hooks解构获得数据
  let {sum,increment,decrement} = useSum()
  let {dogList,getDog} = useDog()
</script>
<style>
    img {
        height: 100px;
    }
</style>

3.App

<template>
     <Hookstest />
</template>

<script lang="ts" setup>
    import Hookstest from './components/HooksTest/hookstest.vue';
</script>

4.与Components的区别

  • 在Hooks里面主要是一些逻辑,不涉及UI,在Components里面主要是一些html结构、css样式、如果要具体的逻辑可以拆分为hooks进行调用,然后进行拼接成一个完整的组件。

网站公告

今日签到

点亮在社区的每一天
去签到