动态和异步组件

阅读: 3768     评论:0

在动态组件上使用 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')
    )
  }
})

 Provide和Inject 模板引用和边界处理 

评论总数: 0


点击登录后方可评论