进行vue3学习跟随尚硅谷vue3

一.vue3简介

Vue是一套用于构建用户界面的渐进式 JavaScript 框架。它由尤雨溪创建,以其易学性、灵活性和高性能而广受欢迎。

“渐进式”意味着你可以:

  • 从一个轻量、核心的库开始,只用于增强静态 HTML。
  • 逐步应用到复杂的、大规模的单页应用。

优点:

  1. 更快的性能:重写了虚拟 DOM,优化了编译策略。
  2. 更小的体积:通过更好的 Tree-shaking(树摇优化),使打包后的文件更小。
  3. 更强的可维护性:采用 Monorepo 管理源码,结构更清晰。
  4. 更好的 TypeScript 支持:使用 TypeScript 重写,提供了完美的类型推断。
  5. 更先进的 API:引入了 Composition API,提供了更好的逻辑复用和组织方式。

二.创建vue3工程

在前端,我们一般使用vscode进行构建

创建vue3工程时,确保自己已经安装了node.js,最新版本可以在官网下载。安装完毕后在桌面打开终端按照如图进行创建最初的vue3工程。

在这里插入图片描述

之后桌面就会出现一个如图所示的文件夹

在这里插入图片描述

之后,将该工程使用vscode打开,系统自动提示安装vue插件,一键安装即可

进入vscode后,发现部分项目标红,打开终端输入npm i下载所有依赖,出现node_modules文件夹,这里面就是我们自动安装的所有依赖。重启后标红消失

此时可以安装插件Vue (Official)
在这里插入图片描述
在这里插入图片描述

文件解释

目录与其中文件介绍:

.vscode/extensions.json是所下载插件

public是页签图标

src是我们主要的工作成果/源代码文件

在这里原先的assets和components文件夹,App.vue需要重新创建,最新版本已经去除

//main.ts文件
//引入creatApp用于创建应用
import { createApp } from "vue";
//引入App根组件
import App from './App.vue'
createApp(App).mount('#app')

文件介绍:

env.d.ts自动声明所有可能用到的的文件

index.html入口文件

两个package包的管理文件

三个tsconfig文件,管理js文件

vite.config.ts安装插件,配置代理

三.vue3核心语法

1.【OptionsAPI 与 CompositionAPI】

特性Options APIComposition API
编程范式选项式、声明式。你告诉 Vue “你需要什么”(data, methods, computed)。函数式、组合式。你像写普通 JavaScript 函数一样组织代码。
代码组织按选项类型组织。相同逻辑的代码被拆分到不同的选项中(如 data, methods, watch)。按逻辑功能组织。所有属于同一功能的代码(响应式数据、方法、计算属性等)可以放在一起。
核心语法data, methods, computed, watch, lifecycle hooks 等选项。ref, reactive, computed, watch, onMounted 等函数。
逻辑复用Mixins / 混入。容易发生命名冲突,来源不清晰,关系不明确。自定义组合式函数。利用纯 JavaScript 函数,返回响应式数据和方法,清晰无冲突。
TypeScript 支持支持较弱,类型推断有时会困难。原生支持极好,能利用完整的 TS 类型推断。
学习曲线较低,对初学者友好,结构固定,易于理解。较高,需要理解响应式原理和函数式编程思想,但灵活性更强。
this 的使用大量使用 this 来访问组件实例的属性和方法。几乎不使用 this。Composition API 的函数在 setup()<script setup> 的范围内直接调用。
适用场景中小型项目,逻辑不复杂的组件,初学者团队。大型项目,需要高复用性、可读性和 TypeScript 支持的重型组件。

vue2中使用的是OptionAPI,而vue3使用的是CompositionAPI

这里测试一个非响应式的demo

仅以该段为例,在vue2中,要将data,methodl分开进行书写,而vue3中可以直接进行初始化,之后的方法分区块书写,最后将所有数据进行提交


<script lang="ts">
  export default {
    name:'Person',
    beforeCreate(){//生命周期
      console.log('beforeCreate')
    },
    setup(){
      console.log(this) //setup中的this是undefined,Vue3在弱化this了
      // 数据,原来是写在data中的,此时的name、age、tel都不是响应式的数据
      let name = '张三'
      let age = 18
      let tel = '13888888888'
      // 方法
      function changeName() {
        name = 'zhang-san' //注意:这样修改name,页面是没有变化的
        console.log(name) //name确实改了,但name不是响应式的
      }
      function changeAge() {
        age += 1 //注意:这样修改age,页面是没有变化的
        console.log(age) //age确实改了,但age不是响应式的
      }
      function showTel() {
        alert(tel)
      }
      // 将数据、方法交出去,模板中才可以使用
      return {name,age,tel,changeName,changeAge,showTel}
    }
  }
</script>

2.setup函数

setup 函数,它是 Composition API 的入口和核心

setup 是一个专门用于使用 Composition API 的组件选项。它在组件实例被创建之前执行,在 beforeCreatecreated 生命周期钩子之前执行。它的主要目的是:

  • 定义响应式数据
  • 定义方法
  • 注册生命周期钩子
  • 返回所有需要在模板中使用的数据和方法

set up中不能用this

3.data,methods,setup能否同时存在于同一组件

data、methods 和 setup 可以同时存在于同一个组件中。Vue 3 设计上完全支持 Options API 和 Composition API 的混合使用。

当三者同时存在时,Vue 会按照以下规则处理:

  1. setup 函数最先执行
  2. data 和 methods 在组件实例创建时合并
  3. 命名冲突时,setup 返回的属性优先级最高,然后是data,methods

<script>
import { ref, computed } from 'vue'
export default {
  // 1. data 选项
  data() {
    return {
      message: 'Hello from data',
      countFromData: 100
    }
  },
  // 2. methods 选项
  methods: {
    incrementFromMethods() {
      this.countFromData += 10
      console.log('Methods count:', this.countFromData)
      console.log('Setup count:', this.count) // 可以访问 setup 返回的数据
    },
    showInfo() {
      console.log('=== 所有数据 ===')
      console.log('data.message:', this.message)
      console.log('data.countFromData:', this.countFromData)
      console.log('setup.count:', this.count)
      console.log('setup.doubleCount:', this.doubleCount)
    }
  },
  // 3. setup 函数
  setup() {
    // setup 中的响应式数据
    const count = ref(0)
    const doubleCount = computed(() => count.value * 2)
    // setup 中的方法
    const incrementFromSetup = () => {
      count.value++
      console.log('Setup count:', count.value)
    }
    // 返回给模板使用的数据和方法
    return {
      count,
      doubleCount,
      incrementFromSetup
    }
  },
  // 其他 Options API 也可以正常使用
  computed: {
    combinedMessage() {
      return `${this.message} - ${this.count}`
    }
  },
  mounted() {
    console.log('组件已挂载')
    console.log('可以在 mounted 中访问所有数据:', this.count, this.message)
  }
}
</script>

4.set up语法糖

<script setup> 是 Vue 3 中 Composition API 的语法糖,它让代码更加简洁、易读,是目前最推荐的写法。在这其中写的东西就相当于写的set up函数

这是普通setup函数

<script>
import { ref, computed } from 'vue'
export default {
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)
    const increment = () => {
      count.value++
    }
    return {
      count,
      double,
      increment
    }
  }
}
</script>

上述代码,还需要编写一个不写setupscript标签,去指定组件名字,比较麻烦,我们可以借助vite中的插件简化

  1. 第一步:npm i vite-plugin-vue-setup-extend -D
  2. 第二步:vite.config.ts在插件包中导入
  3. 第三步:<script setup lang="ts" name="Person">
//使用setup语法糖后
<script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const double = computed(() => count.value * 2)
const increment = () => {
  count.value++
}
</script>

5.响应式数据

5.1ref定义基本类型

ref,这是 Composition API 中最核心的响应式 API 之一,也是 Vue 3 中用于创建响应式引用的函数。它可以包装任何基本类型的值,使其变成响应式的

可以定义基本类型,对象类型的响应式数据

想让谁是响应式,给谁外面包一个ref

语法:let xxx = ref(初始值)

**返回值:**一个RefImpl的实例对象,简称ref对象refref对象的value属性是响应式的

另外,JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用即可。


<script setup>
import { ref } from 'vue'
const count = ref(0)//这里count不是响应式,count.value才是响应式
const increment = () => {
  // 注意:在 JavaScript 中需要通过 .value 访问
  count.value++
  console.log(count.value) // 1
  console.log(count) // RefImpl 对象
}
</script>

5.2reactive响应式对象

reactive 是 Vue 3 中用于创建响应式对象的函数,是 Composition API 中另一个核心的响应式 API。它接收一个普通 JavaScript 对象,并返回该对象的响应式代理。

只能定义对象类型的响应式数据

reactive只要包裹了一个对象,就变成了Proxy()响应式对象

语法:let 响应式对象= reactive(源对象)

**返回值:**一个Proxy的实例对象,简称:响应式对象。

注意点:reactive定义的响应式数据是“深层次”的。

import { reactive } from 'vue'
// 创建响应式对象
const state = reactive({
count: 0,
message: 'Hello',
user: {
name: 'Alice',
age: 25
},
items: ['apple', 'banana']
})

5.3ref 定义对象类型的响应式数据

ref接收的是对象类型,内部其实也是调用了reactive函数。


<script lang="ts" setup name="Person">
import { ref } from 'vue'
// 数据
let car = ref({ brand: '奔驰', price: 100 })
let games = ref([
  { id: 'ahsgdyfa01', name: '英雄联盟' },
  { id: 'ahsgdyfa02', name: '王者荣耀' },
  { id: 'ahsgdyfa03', name: '原神' }
])
let obj = ref({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})
console.log(car)
function changeCarPrice() {
  car.value.price += 10
}
function changeFirstGame() {
  games.value[0].name = '超级鸡马'
}
function test(){
  obj.value.a.b.c.d = 999
}
</script>

5.4ref和reactive对比

特性refreactive
基本定义创建响应式引用,可包装任何值创建响应式对象,仅用于对象类型
数据类型✅ 任何类型:基本类型、对象、数组等❌ 仅对象类型(Object、Array、Map、Set)
创建方式const count = ref(0)const state = reactive({ count: 0 })
访问方式需要通过 .value 访问直接访问属性
模板使用自动解包,无需 .value直接使用属性
重新赋值✅ 支持:ref.value = newValue❌ 不支持直接替换整个对象
解构响应式本身就是引用,解构后仍需要通过 .value需要使用 toRefs 保持响应式
TypeScript 支持✅ 优秀,完整的类型推断⚠️ 一般,复杂嵌套类型推断可能有问题
深度响应式✅ 默认深度响应式✅ 默认深度响应式
性能轻微开销(包装对象)直接 Proxy,性能稍好
适用场景基本类型、需要重新赋值的引用类型、模板 ref复杂的嵌套对象、表单数据、应用状态

5.5toRefs 与 toRef

都是把一个响应式对象里的属性拿出来变成响应式

特性toReftoRefs
作用对象单个响应式对象的单个属性整个响应式对象的所有属性
返回值单个 ref 对象包含所有属性 ref 的对象
使用场景提取单个属性解构整个响应式对象
<template>
  <div class="person">
    <h2>姓名:{{person.name}}</h2>
      <h2>年龄:{{person.age}}{{nl}}</h2>
        <button @click="changeName">修改名字</button>
          <button @click="changeAge">修改年龄</button>
            </div>
              </template>
                <script lang="ts" setup name="Person">
                  import {reactive,toRefs,toRef} from 'vue'
                  // 数据
                  let person = reactive({
                  name:'张三',
                  age:18
                  })
                  // 使用toRefs从person这个响应式对象中,解构出name、age,且name和age依然是响应式的
                  // name和age的值是ref类型,其value值指向的是person.name和person.age
                  let {name,age} = toRefs(person)//toRefs(person)包含name和age
                  let nl = toRef(person,'age')//nl只包含person中的age
                  console.log(nl.value)
                  // 方法
                  function changeName(){
                  name.value += '~'
                  console.log(name.value,person.name)
                  }
                  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;
                      }
                      li {
                      font-size: 20px;
                      }
                      </style>

5.6计算属性comnputed

计算属性是基于响应式依赖进行缓存的派生值,只有当依赖发生变化时才会重新计算。

官网建议:计算属性的返回值应该被视为只读的,并且永远不应该被更改,应该更新它所依赖的源状态以触发新的计算

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
      名:<input type="text" v-model="lastName"> <br>
        全名:<span>{{fullName}}</span> <br>
          <button @click="changeFullName">全名改为:li-si</button>
            </div>
              </template>
                <script setup lang="ts" name="App">
                  import {ref,computed} from 'vue'
                  let firstName = ref('zhang')
                  let lastName = ref('san')
                  // 计算属性——只读取,不修改
                  /* let fullName = computed(()=>{
                  return firstName.value + '-' + lastName.value
                  }) */
                  // 计算属性——既读取又修改
                  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'
                  }
                  </script>

5.7watch监视

watch 用于监听响应式数据的变化,并在变化时执行副作用操作。

vue3只能监视以下四种数据:

  1. ref定义的数据。
  2. reactive定义的数据。
  3. 函数返回一个值(getter函数)。
  4. 一个包含上述内容的数组。
情况一监视ref基本类型数据

<script lang="ts" setup name="Person">
  import {ref,watch} from 'vue'
  // 数据
  let sum = ref(0)
  // 方法
  function changeSum(){
    sum.value += 1
  }
  // 监视,情况一:监视【ref】定义的【基本类型】数据,注意这里sum不用加value
  const stopWatch = watch(sum,(newValue,oldValue)=>{
    console.log('sum变化了',newValue,oldValue)
    if(newValue >= 10){
      stopWatch()
    }
  })
</script>
情况二监视ref对象类型数据

<script lang="ts" setup name="Person">
  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,(newValue,oldValue)=>{
    console.log('person变化了',newValue,oldValue)
  },{deep:true})
  //这里watch第一个对象是person,第二个对象是36行
  //newValue,oldValue有时是一样的,有时不一样
  //这里理解为,你有一个旧房子,现在又买了一个新房子,两个事物是不一样的,但是旧房子地址没有变,所以仍然存在
</script>
情况三监视reactive对象

监视reactive定义的【对象类型】数据,且默认开启了深度监视

隐式创建深层监听,不能关闭


<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})//reactive对象不能整体修改,需要使用assign进行逐个修改
      //简单来说,ref就是重新买个一个房子,建了一个新的对象。而reactive就是把房子装修了,修改了其中值
  }
  function test(){
    obj.a.b.c = 888
  }
  // 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
  watch(person,(newValue,oldValue)=>{
    console.log('person变化了',newValue,oldValue)
  })
  watch(obj,(newValue,oldValue)=>{
    console.log('Obj变化了',newValue,oldValue)
  })
</script>
情况四监视ref或reactive定义的【对象类型】数据中的某个属性

有以下两点注意:

  1. 若该属性值不是【对象类型】,需要写成函数形式。
  2. 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。

监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。


<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>
情况五监视多个数据

<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>

5.8watchEffect

watchEffect 是一个自动依赖追踪的监听器,它会立即执行传入的函数,并自动追踪函数内部使用的所有响应式依赖。

watch监视谁输出谁;watchEffect自动分析监视谁,启动先运行

特性watchwatchEffect
依赖声明显式声明监听源自动追踪依赖
立即执行需要 immediate: true总是立即执行
参数获取提供新旧值不提供参数
使用复杂度相对复杂简单直接
适用场景精确控制监听源自动依赖追踪

<script lang="ts" setup name="Person">
  import {ref,watch,watchEffect} from 'vue'
  // 数据
  let temp = ref(10)
  let height = ref(0)
  // 方法
  function changeTemp(){
    temp.value += 10
  }
  function changeHeight(){
    height.value += 10
  }
  // 监视 -- watch实现
  /* watch([temp,height],(value)=>{
    // 从value中获取最新的水温(newTemp)、最新的水位(newHeight)
    let [newTemp,newHeight] = value
    // 逻辑
    if(newTemp >= 60 || newHeight >= 80){
      console.log('给服务器发请求')
    }
  }) */
  // 监视 -- watchEffect实现
  watchEffect(()=>{
    if(temp.value >= 60 || height.value >= 80){
      console.log('给服务器发请求')
    }
  })
</script>

5.9标签的 ref 属性

作用:用于注册模板引用。

常用

  • 防止样式污染:组件样式不会影响其他组件
  • 避免命名冲突:相同类名在不同组件中互不干扰
  • 组件样式独立:每个组件拥有独立的 CSS 作用域
  • 用在普通DOM标签上,获取的是DOM节点。
  • 用在组件标签上,获取的是组件实例对象。
场景ref 绑定对象返回值类型
DOM 元素<div ref="divRef">HTMLElement
输入框<input ref="inputRef">HTMLInputElement
按钮<button ref="buttonRef">HTMLButtonElement
Vue 组件<Child ref="childRef">组件实例
v-for 中的元素<li v-for ref="listRef">元素数组

5.10props的使用

Props 是组件之间数据传递的一种方式,父组件通过 props 向子组件传递数据。

// 定义一个接口,限制每个Person对象的格式
export interface PersonInter {
id:string,
name:string,
age:number
}
// 定义一个自定义类型Persons
export type Persons = Array<PersonInter>

父亲App.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([
     {id:'e98219e12',name:'张三',age:18},
      {id:'e98219e13',name:'李四',age:19},
       {id:'e98219e14',name:'王五',age:20}
     ])
   </script>

儿子Person.vue中代码:


<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>

6.生命周期(组件的一生)

在 Vue 3 中,生命周期钩子函数是组件在不同阶段执行的函数,让你可以在特定时机执行自定义逻辑。Vue 3 的生命周期与 Vue 2 类似,但有一些变化和组合式 API 的引入。

Vue3中,生命周期分八个阶段,即对应8个与created类似的钩子函数。

  1. setup(组合式 API)
    • 触发时机:在组件实例被创建之初、任何选项式 API 之前执行
    • 主要作用:组合式 API 的入口,定义响应式数据、计算属性、方法等
    • 注意事项:没有对应的选项式 API 钩子
  2. beforeCreate
    • 触发时机:组件实例初始化之后,数据观测和事件/侦听器配置之前
    • 主要作用:执行与响应式数据无关的初始化逻辑
    • 数据状态:数据和方法还未初始化
  3. created
    • 触发时机:组件实例创建完成之后
    • 主要作用:发起异步请求、执行不依赖 DOM 的初始化操作
    • 数据状态:可以访问数据和方法,但尚未挂载到 DOM
  4. beforeMount
    • 触发时机:挂载开始之前,模板编译完成后
    • 主要作用:在组件首次渲染到 DOM 之前执行
    • DOM 状态:this.$el 还不存在
  5. mounted
    • 触发时机:组件挂载到 DOM 之后
    • 主要作用:操作 DOM、初始化第三方库
    • DOM 状态:可以访问到渲染后的 DOM
  6. beforeUnmount(Vue 3)/ beforeDestroy(Vue 2)
    • 触发时机:组件卸载之前
    • 主要作用:清理定时器、取消网络请求、移除事件监听
    • 组件状态:组件实例仍然完全可用
  7. updated
    • 触发时机:数据更改导致虚拟 DOM 重新渲染和打补丁之后
    • 主要作用:执行依赖于 DOM 更新的操作
    • 注意事项:避免在此钩子中修改状态,防止无限循环
  8. unmounted(Vue 3)/ destroyed(Vue 2)
    • 触发时机:组件卸载并销毁之后
    • 主要作用:执行最后的清理工作
    • 组件状态:所有指令和事件监听器已被移除,子组件已被销毁

在这里插入图片描述



<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>

7.自定义hook

自定义 Hook 是一个可重用的函数,用于封装和复用 Vue 组件的逻辑。它基于 Vue 3 的组合式 API,让开发者能够将相关的逻辑代码组织在一起。

示例代码:

  • useSum.ts中内容如下:

    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}
    }
  • useDog.ts中内容如下:

    import {reactive,onMounted} from 'vue'
    import axios,{AxiosError} from 'axios'
    export default function(){
    let dogList = reactive<string[]>([])
      // 方法
      async function getDog(){
      try {
      // 发请求
      let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      // 维护数据
      dogList.push(data.message)
      } catch (error) {
      // 处理错误
      const err = <AxiosError>error
        console.log(err.message)
        }
        }
        // 挂载钩子
        onMounted(()=>{
        getDog()
        })
        //向外部暴露数据
        return {dogList,getDog}
        }
  • 组件中具体使用:

    
    <script lang="ts">
      import {defineComponent} from 'vue'
      export default defineComponent({
        name:'App',
      })
    </script>
    <script setup lang="ts">
      import useSum from './hooks/useSum'
      import useDog from './hooks/useDog'
      let {sum,increment,decrement} = useSum()
      let {dogList,getDog} = useDog()
    </script>