组件保持存活 使用 <component :is="xxx"> 动态切换组件时,会导致组件的状态丢失,比如说在组件 A 中输入了一些内容,然后切换到组件 B,再切换回组件 A,此时组件 A 中的内容就会丢失。
为了解决这个问题,Vue3 提供了一个 <keep-alive> 组件,可以用来对组件进行缓存,从而保持组件的状态不丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <template > <div > <h1 > {{ message }}</h1 > <button @click ="changeMessage" > 改变 message</button > <hr > <keep-alive > <component :is ="componentName" > </component > </keep-alive > <button @click ="changeComponentName" > 切换组件</button > </div > </template > <script > import ComponentA from './ComponentA.vue' import ComponentB from './ComponentB.vue' export default { name : 'App' , components : { ComponentA , ComponentB }, data ( ) { return { message : 'Hello Vue3, I am BeforeCreate' , componentName : 'ComponentA' } }, beforeCreate ( ) { console .log ('beforeCreate' , this .message ) }, created ( ) { console .log ('created' , this .message ) }, beforeMount ( ) { console .log ('beforeMount' , this .message ) }, mounted ( ) { console .log ('mounted' , this .message ) }, beforeUpdate ( ) { console .log ('beforeUpdate' , this .message ) }, updated ( ) { console .log ('updated' , this .message ) }, beforeUnmount ( ) { console .log ('beforeUnmount' , this .message ) }, unmounted ( ) { console .log ('unmounted' , this .message ) }, methods : { changeMessage ( ) { this .message = 'Hello Vue3, I am Updated' }, changeComponentName ( ) { this .componentName = this .componentName === 'ComponentA' ? 'ComponentB' : 'ComponentA' } } } </script >
ComponentA.vue & ComponentB.vue是上一篇笔记中的组件(Login & Register),这里就不再赘述了。
异步组件 大型项目中,可能会有很多组件,如果一次性把所有组件都加载进来,会导致首屏加载时间过长,影响用户体验。
Vue 提供了异步组件的功能,可以让我们把组件按需加载,从而提高首屏加载速度。使用defineAsyncComponent函数来定义异步组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 <template > <div > <h1 > {{ message }}</h1 > <button @click ="changeMessage" > 改变 message</button > <hr > <keep-alive > <component :is ="componentName" > </component > </keep-alive > <button @click ="changeComponentName" > 切换组件</button > <hr > <component :is ="asyncComponentName" > </component > <button @click ="changeAsyncComponentName" > 切换异步组件</button > </div > </template > <script > import ComponentA from './ComponentA.vue' import { defineAsyncComponent } from 'vue' const AsyncComponentB = defineAsyncComponent (() => import ('./ComponentB.vue' ))export default { name : 'App' , components : { ComponentA , AsyncComponentB }, data ( ) { return { message : 'Hello Vue3, I am BeforeCreate' , componentName : 'ComponentA' , asyncComponentName : 'AsyncComponentA' } }, beforeCreate ( ) { console .log ('beforeCreate' , this .message ) }, created ( ) { console .log ('created' , this .message ) }, beforeMount ( ) { console .log ('beforeMount' , this .message ) }, mounted ( ) { console .log ('mounted' , this .message ) }, beforeUpdate ( ) { console .log ('beforeUpdate' , this .message ) }, updated ( ) { console .log ('updated' , this .message ) }, beforeUnmount ( ) { console .log ('beforeUnmount' , this .message ) }, unmounted ( ) { console .log ('unmounted' , this .message ) }, methods : { changeMessage ( ) { this .message = 'Hello Vue3, I am Updated' }, changeComponentName ( ) { this .componentName = this .componentName === 'ComponentA' ? 'ComponentB' : 'ComponentA' }, changeAsyncComponentName ( ) { this .asyncComponentName = this .asyncComponentName === 'AsyncComponentA' ? 'AsyncComponentB' : 'AsyncComponentA' } } } </script >
在浏览器中打开页面,点击切换异步组件按钮,可以看到开发者工具中的Network面板,会发出一个chunk-vendors.js的请求,这个请求就是异步组件的代码。
依赖注入 依赖注入是一种设计模式,它的目的是为了提高代码的可复用性。
通常,我们要从父组件向子组件传递数据,需要使用props,但是如果父组件和子组件之间的层级很深,那么就需要一层一层的传递props,这样会导致代码的可维护性变差。
这一问题被称为prop drilling,Vue3 提供了依赖注入的功能,可以解决这一问题。
provide和inject是成对使用的,provide用来提供数据,inject用来注入数据。一个父组件相对其所有后代组件,会作为一个provide的来源,而所有的子组件都可以使用inject来注入数据。
新建一个components文件夹,然后在里面新建一个Grandson.vue、Son.vue和Father.vue,代码如下:
Grandson.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 <template > <div > <h1 > Grandson</h1 > <p > message: {{ message }}</p > </div > </template > <script > export default { name : 'Grandson' , inject : ['message' ] } </script >
Son.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <template > <div > <h1 > Son</h1 > <p > message: {{ message }}</p > <Grandson > </Grandson > </div > </template > <script > import Grandson from './Grandson.vue' export default { name : 'Son' , components : { Grandson }, inject : ['message' ] } </script >
Father.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template > <div > <h1 > Father</h1 > <p > message: {{ message }}</p > <Son > </Son > </div > </template > <script > import Son from './Son.vue' export default { name : 'Father' , components : { Son }, provide ( ) { return { message : 'Hello Vue3, I am provide' } } } </script >
在Father.vue中,我们使用provide来提供数据,然后在Son.vue和Grandson.vue中使用inject来注入数据。
Father 的 message 没有显示出来,控制台提示 [Vue warn]: Property "message" was accessed during render but is not defined on instance.,这是因为provide提供的数据,只能在后代组件中使用,不能在自己组件中使用。
并且,provide提供的数据,只能在后代组件中使用,不能在兄弟组件中使用。也就是从上到下的单向数据流。
如果想要一个全局的数据,可以在main.js中使用app.provide来提供数据,然后在组件中使用inject来注入数据。
main.js
1 2 3 4 5 6 7 8 import { createApp } from 'vue' import App from './App.vue' const app = createApp (App )app.provide ('message' , 'Hello Vue3, I am provide' ) app.mount ('#app' )
Vue 应用 main.js中的代码如下:
1 2 3 4 5 6 7 8 9 10 import { createApp } from 'vue' const app = createApp ({ }) app.mount ('#app' )
应用实例
每个 Vue 应用都需要通过 createApp 函数来创建一个应用实例,然后通过 mount 函数来挂载应用实例。
根组件
在 Vue 应用中,我们需要定义一个根组件,这个根组件会被挂载到 #app 元素中,这个根组件可以包含其他的子组件。
挂载点
在 Vue 应用中,我们需要一个挂载点,这个挂载点是一个 DOM 元素,我们可以通过这个挂载点来把根组件挂载到 DOM 中。
🎉结束这一段学习 Vue3 的学习到此结束。Vue3 的学习笔记就到这里!