keep-alive
我们之前曾经在一个多标签的界面中使用 is
属性来切换不同的组件:
<component :is="currentTabComponent"></component>
component
标签不是HTML原生的,而是Vue设计的。
我们看下面的例子:
<div id="dynamic-component-demo" class="demo"> <button v-for="tab in tabs" :key="tab" :class="['tab-button', { active: currentTab === tab }]" @click="currentTab = tab" > {{ tab }} </button> <component :is="currentTabComponent" class="tab"></component> </div>
const app = Vue.createApp({ data() { return { currentTab: 'Home', tabs: ['Home', 'Posts', 'Archive'] } }, computed: { currentTabComponent() { return 'tab-' + this.currentTab.toLowerCase() } } }) app.component('tab-home', { template: `<div class="demo-tab">Home component</div>` }) app.component('tab-posts', { template: `<div class="dynamic-component-demo-posts-tab"> <ul class="dynamic-component-demo-posts-sidebar"> <li v-for="post in posts" :key="post.id" :class="{ 'dynamic-component-demo-active': post === selectedPost }" @click="selectedPost = post" > {{ post.title }} </li> </ul> <div class="dynamic-component-demo-post-container"> <div v-if="selectedPost" class="dynamic-component-demo-post"> <h3>{{ selectedPost.title }}</h3> <div v-html="selectedPost.content"></div> </div> <strong v-else> Click on a blog title to the left to view it. </strong> </div> </div>`, data() { return { posts: [ { id: 1, title: 'Cat Ipsum', content: '<p>Dont wait for the storm to pass, ......</p>' }, { id: 2, title: 'Hipster Ipsum', content: '<p>Bushwick blue bottle scenester helvetica ugh, .......</p>' }, { id: 3, title: 'Cupcake Ipsum', content: '<p>Icing dessert soufflé lollipop chocolate bar sweet tart cake chupa chups. ......</p>' } ], selectedPost: null } } }) app.component('tab-archive', { template: `<div class="demo-tab">Archive component</div>` }) app.mount('#dynamic-component-demo')
现在我们有Home、Posts、Archive三个组件,其中的Home和Archive就是做个样子,主要还是Posts组件。
Posts组件有个列表,点击任何一个,就会显示其具体内容。
问题在于,假设你当前在看Cat Ipsum这个blog,突然想切换到Home页面去看一下,看完后,又切回来,然后你会发现,你先前看的文章没了,Posts组件回到了初始状态。
通俗的例子就是你在手机上用app看小说,临时切换去看了眼微信,再切回来发现小说关闭了,你不但得重新打开小说,还要自己去找已经看到的章节。
这种场景就需要我们能够缓存组件的状态,Vue提供了一个自己设计的 <keep-alive>
标签以实现该功能。
<!-- 失活的组件将会被缓存!--> <keep-alive> <component :is="currentTabComponent"></component> </keep-alive>
可以自行测试,查看具体效果。
动态组件是已经加载好了组件,然后在组件中进行切换。
异步组件则是按需加载,没到我上场的时候,我就在后台先歇着。
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。
为了简化代码,Vue 提供了一个 defineAsyncComponent
方法:
const { createApp, defineAsyncComponent } = Vue const app = createApp({}) const AsyncComp = defineAsyncComponent( () => new Promise((resolve, reject) => { resolve({ template: '<div>I am async!</div>' }) }) ) app.component('async-example', AsyncComp)
如你所见,此方法接受一个返回 Promise
的工厂函数。从服务器检索组件定义后,应调用 Promise 的 resolve
回调。你也可以调用 reject(reason)
,来表示加载失败。
把 webpack 2 和 ES2015 语法相结合后,我们可以实现异步导入模块:
import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => import('./components/AsyncComponent.vue') ) app.component('async-component', AsyncComp)
当在局部注册组件时,你也可以使用 defineAsyncComponent
import { createApp, defineAsyncComponent } from 'vue' createApp({ // ... components: { AsyncComponent: defineAsyncComponent(() => import('./components/AsyncComponent.vue') ) } })