VUE3学习笔记(根据黑马教程总结)

Vue 3 学习笔记

目录

  1. Vue 3 与 Vue 2 的区别
  2. Vite
  3. 组合式 API 基础
  4. Vue Router
  5. Pinia
  6. 组件通信
  7. 响应式进阶 API
  8. Vue 3 新组件与全局 API

1. Vue 3 与 Vue 2 的区别

1.1 性能提升

  • 打包体积更小、渲染更快、内存占用更少。

1.2 源码升级

  • 使用 Proxy 替代 Object.defineProperty 实现响应式,能监听属性新增 / 删除、数组索引与 length 变化。
  • 重写虚拟 DOM 的实现,并支持 Tree-Shaking(按需引入,未使用的 API 不进入产物)。

1.3 更好地支持 TypeScript

源码使用 TypeScript 重写,类型推导与 IDE 提示更完整。

1.4 新特性:选项式 API → 组合式 API

  • setup 语法糖(<script setup>):允许把同一个功能逻辑写在一起,不再按 data / methods / computed 拆散。
  • ref 与 reactive:定义响应式数据。
  • computed 与 watch:计算属性与侦听器。
  • 新内置组件:Fragment(支持多根节点)、Teleport、Suspense。

1.5 其他变化

  • 生命周期钩子重命名:beforeDestroy → beforeUnmount,destroyed → unmounted。
  • 移除实例方法 $on、$off、$once,官方推荐使用 mitt 等外部库替代事件总线。
  • 创建应用的方式从 new Vue() 变为 createApp()(从 vue 导入)。
  • 过渡类名 v-enter 改为 v-enter-from,v-leave 改为 v-leave-from。
  • 移除 keyCode 作为 v-on 修饰符的支持,改用按键别名(如 @keyup.enter)。
  • 组件上的 v-model 被重新设计,替换掉 v-bind.sync,改用带参数的 v-model。
  • v-if 和 v-for 用在同一个元素上时,优先级发生变化:Vue 3 中 v-if 优先于 v-for。
  • 移除过滤器 filter,改用计算属性或方法。
  • 移除 $children 实例属性(property)。

2. Vite

2.1 特点

  • 支持 TS、JSX、CSS 等,开箱即用;轻量快速。
  • 热更新(HMR),按需编译,只更新修改的模块。

2.2 Vite 与 Webpack 的区别

Webpack 是「先打包再启动」,Vite 是「先启动再按需编译」。

Webpack Vite
启动 先打包全部模块,再启动开发服务器 先启动开发服务器,浏览器请求到某模块时才编译
依据 打包后的 bundle 浏览器原生 ESM
体验 项目越大冷启动越慢 冷启动快,HMR 只更新改动模块

补充:Vite 的「不打包」只针对开发阶段;生产构建仍会用 Rollup 打包。


3. 组合式 API 基础

3.1 setup

  • setup 函数会在 beforeCreate 之前调用,领先所有生命周期钩子执行。
  • setup 返回的对象中的内容,可直接在模板中使用。

3.2 toRefs 与 toRef

作用 :将一个响应式对象中的每一个属性转换为 ref 对象。

ts 复制代码
let person = reactive({ name: '张三', age: 18, gender: '男' })

// 通过 toRefs 将 person 对象中的 n 个属性批量取出,且依然保持响应式能力
let { name, gender } = toRefs(person)

// 通过 toRef 将 person 对象中的 age 属性取出,且依然保持响应式能力
let age = toRef(person, 'age')

toRefs 与 toRef 功能一致,但 toRefs 可以批量转换。

3.3 computed

  • computed 追踪函数内部的所有响应式数据进行计算,只要其中一个发生变化就会重新计算;带有缓存机制。
  • 只读取、不修改时,直接写简写形式:
ts 复制代码
const doubleSum = computed(() => sum.value * 2)
  • 希望直接修改这个计算属性,并且修改能反向影响它依赖的源数据 时,需要写成对象形式,在 computed 里提供 get 和 set:
ts 复制代码
const fullName = computed({
  get() {
    return firstName.value + '-' + lastName.value
  },
  set(value: string) {
    const [first, last] = value.split('-')
    firstName.value = first
    lastName.value = last
  }
})

怎么选 :需要根据已有数据「算」出一个新值且希望有缓存,用 computed;需要响应用户操作(如点击)执行动作,用 methods(或直接定义函数);需要监听某个数据变化后去做别的事(比如请求接口),用 watch。

3.4 watch

作用 :监视数据的变化(与 Vue 2 中的 watch 作用一致)。

Vue 3 中 watch 的第一个参数只能是以下四种数据:

  1. ref 定义的数据。
  2. reactive 定义的数据(默认是深度监视)。
  3. 函数返回一个值(getter 函数)。
  4. 一个包含上述内容的数组。

情况一:监视 ref 定义的【基本类型】数据

ts 复制代码
const stopWatch = watch(sum, (newValue, oldValue) => {
  console.log('sum变化了', newValue, oldValue)
  if (newValue >= 10) {
    stopWatch()
  }
})

watch API 返回一个停止函数(stop handle),调用它就会停止监听。回调执行时 stopWatch 已经完成赋值,所以可以在回调内部通过闭包直接调用它。

第三个参数:配置对象

ts 复制代码
watch(source, callback, { deep: true, immediate: true })
  • deep:深度监视。
  • immediate:立即执行,在初始绑定时就先执行一次。

监视对象里的某个属性:最好写成函数式(getter)

ts 复制代码
watch(() => person.car, (newValue, oldValue) => {
  console.log('person.car变化了', newValue, oldValue)
}, { deep: true })

注意点:直接监视一个 reactive 对象时默认就是深度监视;但用 getter 返回一个对象时,默认只比较引用值(地址),要关注对象内部属性的变化,需要手动开启 deep: true。

3.5 watch 对比 watchEffect

两者都能监听响应式数据的变化,不同的只是监听数据的方式:

watch watchEffect
指定数据源 要明确指出监视的数据 不用明确指出,函数中用到哪些属性就监视哪些
执行时机 默认懒执行,数据变化才回调 立即执行一次,之后依赖变化再执行
拿到的值 能拿到 newValue / oldValue 拿不到旧值

3.6 标签的 ref 属性

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

  • 用在普通 DOM 标签上,获取的是 DOM 节点。
  • 用在组件标签上,获取的是组件实例对象。

3.7 自定义 hook

  • 本质是一个函数,里面封装了状态(数据)和操作状态的逻辑(方法)。
  • 约定 以 use 开头(如 useUser、useFetch),本身是一个普通 JS 函数,并非语法强制。
  • 内部可以使用 Vue 的 API,最后返回一个数据或者函数供组件使用。

4. Vue Router

4.1 基本使用

在 main.ts 里挂载 router:

ts 复制代码
const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/home', component: Home },
    { path: '/about', component: About }
  ]
})
vue 复制代码
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterView></RouterView> <!-- 路由出口 -->
  • 路由组件通常存放在 pages 或 views 文件夹,一般组件通常存放在 components 文件夹。
  • 通过点击导航,视觉效果上「消失」了的路由组件,默认是被卸载掉的,需要的时候再去挂载(可用 KeepAlive 缓存)。

4.2 路由工作模式

模式 创建函数 URL 注意点
history createWebHistory() 不带 # 后期项目上线需要服务端配合处理路径,否则刷新 404
hash createWebHashHistory() 带 # 无需服务端配合,但在 SEO 优化方面较差

4.3 命名路由与 to 的两种写法

命名路由可以简化路由跳转及传参。

vue 复制代码
<!-- 第一种:to 的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>

<!-- 第二种:to 的对象写法,可以传 path,也可以传 name -->
<router-link active-class="active" :to="{ path: '/home' }">Home</router-link>
<router-link :to="{ name: 'xiang' }">详情</router-link>

4.4 路由传参:query 参数

1. 传递参数

vue 复制代码
<!-- 跳转并携带 query 参数(to 的字符串写法) -->
<router-link to="/news/detail?a=1&b=2&content=欢迎你">
  跳转
</router-link>

<!-- 跳转并携带 query 参数(to 的对象写法) -->
<RouterLink
  :to="{
    // name:'xiang', // 用 name 也可以跳转
    path: '/news/detail',
    query: {
      id: news.id,
      title: news.title,
      content: news.content
    }
  }"
>
  {{ news.title }}
</RouterLink>

2. 接收参数

ts 复制代码
import { useRoute } from 'vue-router'

const route = useRoute()
// 打印 query 参数
console.log(route.query)

4.5 路由传参:params 参数

1. 传递参数

vue 复制代码
<!-- 跳转并携带 params 参数(to 的字符串写法) -->
<RouterLink :to="`/news/detail/001/新闻001/内容001`">{{ news.title }}</RouterLink>

<!-- 跳转并携带 params 参数(to 的对象写法) -->
<RouterLink
  :to="{
    name: 'xiang', // 用 name 跳转
    params: {
      id: news.id,
      title: news.title,
      content: news.content
    }
  }"
>
  {{ news.title }}
</RouterLink>

2. 接收参数

ts 复制代码
import { useRoute } from 'vue-router'

const route = useRoute()
// 打印 params 参数
console.log(route.params)

备注 1:传递 params 参数时,若使用 to 的对象写法,必须使用 name 配置项,不能用 path。

备注 2:传递 params 参数时,需要提前在路由规则中占位(如 detail/:id/:title/:content)。Vue Router 4 中,未在规则里声明的 params 会被忽略。

4.6 路由的 props 配置

js 复制代码
{
  name: 'xiang',
  path: 'detail/:id/:title/:content',
  component: Detail,

  // props 的对象写法,作用:把对象中的每一组 key-value 作为 props 传给 Detail 组件
  // props: { a: 1, b: 2, c: 3 },

  // props 的布尔值写法,作用:把收到的每一组 params 参数,作为 props 传给 Detail 组件
  // props: true,

  // props 的函数写法,作用:把返回的对象中每一组 key-value 作为 props 传给 Detail 组件
  props(route) {
    return route.query
  }
}

4.7 编程式导航

ts 复制代码
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()    // 当前路由信息
const router = useRouter()  // 路由器实例

console.log(route.query)
console.log(route.params)
console.log(router.push)
console.log(router.replace)
  • route 只能看不能改,用来获取当前页面信息。
  • router 可以进行路由导航,修改路由地址进行页面跳转。

4.8 重定向

重定向就是将特定的路径重新定位到已有路由,用 redirect 配置。例如检测到用户没登录,将用户导航到登录页。

js 复制代码
{ path: '/', redirect: '/home' }

5. Pinia

管理全局数据的仓库。

5.1 三个核心概念

  1. Store 是一个保存状态 、业务逻辑 的实体,每个组件都可以读取 、写入它。
  2. 它有三个概念:state、getter、action,相当于组件中的 data、computed 和 methods。
  3. 定义时给 defineStore 传一个唯一 id(如 'count'),并导出 useXxxxxStore。

5.2 定义 store

具体编码:src/store/count.ts

ts 复制代码
// 引入 defineStore 用于创建 store
import { defineStore } from 'pinia'

// 定义并暴露一个 store
export const useCountStore = defineStore('count', {
  // 动作
  actions: {},
  // 状态
  state() {
    return {
      sum: 6
    }
  },
  // 计算
  getters: {}
})

具体编码:src/store/talk.ts

ts 复制代码
// 引入 defineStore 用于创建 store
import { defineStore } from 'pinia'

// 定义并暴露一个 store
export const useTalkStore = defineStore('talk', {
  // 动作
  actions: {},
  // 状态
  state() {
    return {
      talkList: [
        { id: 'yuysada01', content: '你今天有点怪,哪里怪?怪好看的!' },
        { id: 'yuysada02', content: '草莓、蓝莓、蔓越莓,你想我了没?' },
        { id: 'yuysada03', content: '心里给你留了一块地,我的死心塌地' }
      ]
    }
  },
  // 计算
  getters: {}
})

5.3 组件中使用 state 中的数据

vue 复制代码
<template>
  <h2>当前求和为:{{ sumStore.sum }}</h2>
</template>

<script setup lang="ts" name="Count">
  // 引入对应的 useXxxxxStore
  import { useSumStore } from '@/store/sum'

  // 调用 useXxxxxStore 得到对应的 store
  const sumStore = useSumStore()
</script>
vue 复制代码
<template>
  <ul>
    <li v-for="talk in talkStore.talkList" :key="talk.id">
      {{ talk.content }}
    </li>
  </ul>
</template>

<script setup lang="ts" name="Talk">
  import { useTalkStore } from '@/store/talk'

  const talkStore = useTalkStore()
</script>

注意:课程示例里 count.ts 导出的是 useCountStore,组件中却写 useSumStore / @/store/sum,属于示例命名不一致。实际项目里文件名、store id、导出名、导入路径要保持一致。

5.4 修改数据(三种方式)

第一种:直接修改

ts 复制代码
countStore.sum = 666

第二种:批量修改 $patch

ts 复制代码
countStore.$patch({
  sum: 999,
  school: 'atguigu'
})

第三种:借助 action 修改 (action 中可以编写一些业务逻辑)

ts 复制代码
import { defineStore } from 'pinia'

export const useCountStore = defineStore('count', {
  /*************/
  actions: {
    // 加
    increment(value: number) {
      if (this.sum < 10) {
        // 操作 countStore 中的 sum
        this.sum += value
      }
    },
    // 减
    decrement(value: number) {
      if (this.sum > 1) {
        this.sum -= value
      }
    }
  },
  /*************/
})

组件中调用 action 即可:

ts 复制代码
// 使用 countStore
const countStore = useCountStore()

// 调用对应 action
countStore.increment(n.value)

5.5 常用配套 API

  • storeToRefs:将 store 中的数据转为 ref 对象,解构后不丢失响应式,方便在模板中使用。
  • $subscribe():通过 store 的该方法侦听 state 及其变化。
  • nanoid():轻量的唯一 ID 生成库(不是组件库),常用来给列表项生成 id。
  • 使用 setup 语法定义 store 时,只有 return 出去的东西,组件里才能使用;选项式 defineStore 则由 state / getters / actions 自动暴露。

5.6 Pinia 与 mitt 的区别

Pinia mitt
适合 管理长期存在的全局状态(如用户登录信息、购物车) 处理瞬时的动作通知
是否保存数据 保存并管理状态,组件可读写 不保存状态,只转发事件
典型场景 多组件共享同一份数据 一次性的跨组件事件通知

6. 组件通信

6.1 props:父组件向子组件传递数据

父组件里,在引入子组件的地方写:

vue 复制代码
<Person :list="persons" />

persons 就是要传的值,list 是在子组件里定义的属性名。

子组件的三种接收写法:

ts 复制代码
// 第一种写法:仅接收
// list 是子组件内部通过 defineProps 声明好要接收的属性名
const props = defineProps(['list'])

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

// 第三种写法:接收 + 限制类型 + 指定默认值 + 限制必要性
let props = withDefaults(defineProps<{ list?: Persons }>(), {
  list: () => [{ id: 'asdasg01', name: '小猪佩奇', age: 18 }]
})

注意:HTML 原生属性对大小写不敏感。所以父组件传值时,如果子组件声明的是驼峰命名(比如 userList),父组件写的时候通常要改成短横线分隔(:user-list="users")。

6.2 emit:子传父

子组件里 defineEmits,然后再调用:

ts 复制代码
const emit = defineEmits(['sendMsg'])
emit('sendMsg', msg.value)

父组件里监听 sendMsg 事件,触发时执行 getData 函数:

vue 复制代码
<Son @send-msg="getData" />

6.3 mitt:任意组件通信

新建一个文件(比如 src/utils/bus.ts),把 mitt 实例化并导出去,这样所有组件都能共用这一个实例。

ts 复制代码
// src/utils/bus.ts
import mitt from 'mitt'

// 定义事件类型(可选,但结合 TS 很好用)
type Events = {
  sendMsg: string                           // 事件名:sendMsg,传参类型:字符串
  updateUser: { id: number, name: string }  // 事件名:updateUser,传参类型:对象
}

const bus = mitt<Events>()
export default bus

ComponentA.vue(发送)

vue 复制代码
<template>
  <button @click="sendMessage">给组件B发消息</button>
</template>

<script setup lang="ts">
import bus from '@/utils/bus'

function sendMessage() {
  // 使用 bus.emit('事件名', 传递的数据)
  bus.emit('sendMsg', '你好,我是组件A!')
}
</script>

ComponentB.vue(接收)

vue 复制代码
<template>
  <div>接收到的消息:{{ msg }}</div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import bus from '@/utils/bus'

const msg = ref('暂无消息')

// 必须在组件挂载时开始监听
onMounted(() => {
  bus.on('sendMsg', (data) => {
    console.log('组件B收到了:', data)
    msg.value = data
  })
})

// 一定要在 onUnmounted 生命周期里关掉它,否则会内存泄漏
onUnmounted(() => {
  // 关闭指定事件的监听
  bus.off('sendMsg')

  // 或者清空所有事件监听:
  // bus.all.clear()
})
</script>

6.4 v-model:父子通信

组件标签上的 v-model 的本质::modelValue 加 update:modelValue 事件。

6.5 $attrs:祖 → 孙

$attrs 用于实现当前组件的父组件,向当前组件的子组件通信(祖 → 孙)。

$attrs 是一个对象,包含所有父组件传入、但未被当前组件 props 声明接收的标签属性。中间组件用 v-bind="$attrs" 一次性透传即可。

父组件:

vue 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
    <Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA" />
  </div>
</template>

<script setup lang="ts" name="Father">
  import Child from './Child.vue'
  import { ref } from 'vue'

  let a = ref(1)
  let b = ref(2)
  let c = ref(3)
  let d = ref(4)

  function updateA(value: number) {
    a.value = value
  }
</script>

子组件:

vue 复制代码
<template>
  <div class="child">
    <h3>子组件</h3>
    <GrandChild v-bind="$attrs" />
  </div>
</template>

<script setup lang="ts" name="Child">
  import GrandChild from './GrandChild.vue'
</script>

孙组件:

vue 复制代码
<template>
  <div class="grand-child">
    <h3>孙组件</h3>
    <h4>a:{{ a }}</h4>
    <h4>b:{{ b }}</h4>
    <h4>c:{{ c }}</h4>
    <h4>d:{{ d }}</h4>
    <h4>x:{{ x }}</h4>
    <h4>y:{{ y }}</h4>
    <button @click="updateA(666)">点我更新A</button>
  </div>
</template>

<script setup lang="ts" name="GrandChild">
  defineProps(['a', 'b', 'c', 'd', 'x', 'y', 'updateA'])
</script>

注意:中间的子组件中不用编写任何东西,是不受到任何打扰的。

6.6 refs / parent

  • $refs 用于:父 → 子。
  • $parent 用于:子 → 父。
属性 说明
$refs 值为对象,包含所有被 ref 属性标识的 DOM 元素或组件实例
$parent 值为对象,当前组件的父组件实例对象

补充:在 <script setup> 中这两个实例属性不会直接暴露,需要 getCurrentInstance();实际项目更推荐用模板 ref、props / emit 或 provide / inject。

6.7 provide / inject

概述 :实现祖孙组件直接通信。

具体使用:

  • 在祖先组件中通过 provide 配置向后代组件提供数据。
  • 在后代组件中通过 inject 配置来声明接收数据。

【第一步】父组件中,使用 provide 提供数据

vue 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
    <h4>资产:{{ money }}</h4>
    <h4>汽车:{{ car }}</h4>
    <button @click="money += 1">资产+1</button>
    <button @click="car.price += 1">汽车价格+1</button>
    <Child />
  </div>
</template>

<script setup lang="ts" name="Father">
  import Child from './Child.vue'
  import { ref, reactive, provide } from 'vue'

  // 数据
  let money = ref(100)
  let car = reactive({
    brand: '奔驰',
    price: 100
  })

  // 用于更新 money 的方法
  function updateMoney(value: number) {
    money.value += value
  }

  // 提供数据
  provide('moneyContext', { money, updateMoney })
  provide('car', car)
</script>

注意:中间子组件中不用编写任何东西,是不受到任何打扰的。

【第二步】孙组件中使用 inject 接收数据

vue 复制代码
<template>
  <div class="grand-child">
    <h3>我是孙组件</h3>
    <h4>资产:{{ money }}</h4>
    <h4>汽车:{{ car }}</h4>
    <button @click="updateMoney(6)">点我</button>
  </div>
</template>

<script setup lang="ts" name="GrandChild">
  import { inject } from 'vue'

  // 注入数据,第二个参数是找不到 provider 时的默认值
  let { money, updateMoney } = inject('moneyContext', {
    money: 0,
    updateMoney: (x: number) => {}
  })
  let car = inject('car')
</script>

补充:在 TS 里 inject('car') 不带默认值时类型会包含 undefined,建议传入默认值或用类型参数明确类型。

6.8 插槽 slot

  • 默认插槽 :<slot></slot>。
  • 具名插槽 :子组件写 <slot name="s1"></slot>,父组件在引用子组件时用 <template v-slot:s1>(或 #s1)填充。
  • 作用域插槽:数据在组件自身,但根据数据生成的结构需要组件的使用者来决定。

具体编码:

父组件中:

vue 复制代码
<Game v-slot="params">
<!-- <Game v-slot:default="params"> -->
<!-- <Game #default="params"> -->
  <ul>
    <li v-for="g in params.games" :key="g.id">{{ g.name }}</li>
  </ul>
</Game>

子组件中:

vue 复制代码
<template>
  <div class="category">
    <h2>今日游戏榜单</h2>
    <slot :games="games" a="哈哈"></slot>
  </div>
</template>

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

  let games = reactive([
    { id: 'asgdytsa01', name: '英雄联盟' },
    { id: 'asgdytsa02', name: '王者荣耀' },
    { id: 'asgdytsa03', name: '红色警戒' },
    { id: 'asgdytsa04', name: '斗罗大陆' }
  ])
</script>

7. 响应式进阶 API

7.1 总览

API 作用
shallowRef 创建一个响应式数据,但只对顶层做响应式处理:只跟踪 .value 整体替换,不关心值内部的属性变化
shallowReactive 创建一个浅层响应式对象,只让对象的最顶层属性变成响应式,嵌套属性不是
readonly 用于创建一个对象的深只读副本
shallowReadonly 只将对象的最顶层属性设置为只读,内部的嵌套属性仍然可以修改
toRaw 获取一个响应式对象的原始对象;返回的对象不再是响应式的,不会触发视图更新
markRaw 标记一个对象,使其永远不会变成响应式的
  • shallowRef / shallowReactive 是用来做性能优化的:ref / reactive 的深度监听在面对巨大数据时会有开销。
  • toRaw 在需要将响应式数据传给非 Vue 的库或者外部系统时使用,确保对方收到的是普通对象。

7.2 customRef

作用 :创建一个自定义的 ref,并对其依赖项跟踪(track)和更新触发(trigger)进行逻辑控制。

实现防抖效果(useSumRef.ts):

ts 复制代码
import { customRef } from 'vue'

export default function (initValue: string, delay: number) {
  let msg = customRef((track, trigger) => {
    let timer: number
    return {
      get() {
        track() // 告诉 Vue 数据 msg 很重要,要对 msg 持续关注,一旦变化就更新
        return initValue
      },
      set(value) {
        clearTimeout(timer)
        timer = setTimeout(() => {
          initValue = value
          trigger() // 通知 Vue 数据 msg 变化了
        }, delay)
      }
    }
  })
  return { msg }
}

8. Vue 3 新组件与全局 API

8.1 Teleport

Teleport 是一种能够将我们的组件 HTML 结构移动到指定位置的技术。

html 复制代码
<teleport to='body'>
  <div class="modal" v-show="isShow">
    <h2>我是一个弹窗</h2>
    <p>我是弹窗中的一些内容</p>
    <button @click="isShow = false">关闭弹窗</button>
  </div>
</teleport>

8.2 Suspense

等待异步组件时渲染一些额外内容,让应用有更好的用户体验。

使用步骤:

  1. 异步引入组件。
  2. 使用 Suspense 包裹组件,并配置好 default 与 fallback 两个插槽。
ts 复制代码
import { defineAsyncComponent } from 'vue'

const Child = defineAsyncComponent(() => import('./Child.vue'))
vue 复制代码
<template>
  <div class="app">
    <h3>我是App组件</h3>
    <Suspense>
      <template v-slot:default>
        <Child />
      </template>
      <template v-slot:fallback>
        <h3>加载中.......</h3>
      </template>
    </Suspense>
  </div>
</template>

Suspense 是内置组件,不需要从 vue 导入。

8.3 全局 API 转移到应用对象

  • app.component
  • app.config
  • app.directive
  • app.mount
  • app.unmount
  • app.use

相关推荐
wangqiaowq3 小时前
Ontology 学习
学习
choumou_M5 小时前
算法_1:由浅入深学习快速排序QuickSort
学习·算法·排序算法
一壶浊酒伴余生7 小时前
新概念英语第一册 · 句法笔记
笔记·英语学习·英语语法·新概念英语
蒸蒸yyyyzwd10 小时前
后端学习笔记 day111
笔记·学习
叼烟扛炮10 小时前
[LangChain] 学习笔记(08):工具调用底层闭环与第三方搜索(Tavily)实战
人工智能·笔记·学习·langchain
Century_Dragon11 小时前
让新能源故障诊断实训“触手可及“——仿真教学软件(VR)介绍
学习
江屿风11 小时前
【Git-组件】【Git入门:从文档灾难到版本掌控】流食般投喂
运维·笔记·git·组件·版本控制
楚山之石12 小时前
【Radiology】影像组学的标准化与可重复性:IBSI 卷积滤波器共识及其未能覆盖的环节
人工智能·学习·机器学习·mri
小李不想当小白13 小时前
HAL库之UART(STM32 HAL库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
旖旎夜光14 小时前
【C++ 基础入门】C++ 多态(中):虚函数表、多态原理与动静绑定
开发语言·c++·笔记·学习