Blog icon indicating copy to clipboard operation
Blog copied to clipboard

【翻译】Vue动态组件

Open pramper opened this issue 9 years ago • 0 comments

翻译自 Dynamic Components in Vue.js

这篇文章将会教你如何使用Vue中的动态组件。当创建小型的单页应用时,这些小型应用可能并不需要vue-router来控制路由,我们只想简单地切换不同的组件来达到不同的展示效果。

Vue中的动态组件要求你指定一个挂载点,在这个挂载点下你可以动态地切换组件。在这篇教程中,我们将通过几个例子来展示如何使用动态组件。我们会创建一个动态组件,学习使用keep-alive指令参数,最后我们还会在组件的切换之间添加一些过渡效果。下面开始吧:

创建动态组件

假设我们正在为一个Blog做个简单的导航栏,我们想添加两个页面:

  • 一个用于管理已经存在的博客文章
  • 一个用于创建新的博客文章

稍后,我们会组件化这两个页面。现在,让我们从头一步步来吧,我们把这个简单的应用挂载到body下:

new Vue({
  el: 'body'
})

添加导航栏,在头部引入BootStrop 3.3.6

<div class="header clearfix">
  <nav>
    <ul class="nav nav-pills pull-right">
      <li role="presentation">
        <a href="javascript:void(0)">Manage Posts</a>
      </li>
      <li role="presentation">
        <a href="javascript:void(0)">Create Post</a>
      </li>
    </ul>
  </nav>
  <h3 class="text-muted">Admin Panel</h3>
</div>

<div class="container">
  <!-- render the currently active component/page here -->
</div>

运行程序,我们会得到如下图所示的效果:

现在,我们这个小小的应用已经有了一个大概的结构,下面我们开始创建两个组件:一个用于管理已经存在的博客文章,一个用于创建新的博客文章。如果你还不了解如何在Vue中创建组件,建议你看看这个教程,或者看官方的教程,那里已经说得够明白了。

下面创建一个manage-posts组件,并模拟一些文章标题数据:

Vue.component('manage-posts', {
  template: '#manage-template',
  data: function() {
    return {
      posts: [
        'Vue.js: The Basics',
        'Vue.js Components',
        'Server Side Rendering with Vue',
        'Vue + Firebase'
      ]
    }
  }
})

接着为组件manage-posts创建一个模板:

<template id="manage-template">
  <div>
    <h1>Manage Posts</h1>
    <div class="list-group">
      <a v-for="post in posts" href="#" class="list-group-item clearfix">
        {{ post }}
        <span class="pull-right">
          <button class="btn btn-xs btn-info">
            <span class="glyphicon glyphicon-edit"></span>
          </button>
          <button class="btn btn-xs btn-warning">
            <span class="glyphicon glyphicon-trash"></span>
          </button>
        </span>
      </a>
    </div>
  </div>
</template>

效果

目前为止,我们已经有了导航栏和mange-posts组件,下面我们添加create-post组件,并把它们结合起来:

Vue.component('create-post', {
  template: '#create-template'
})

模板:

<template id="create-template">
  <div>
    <h1>Create Post</h1>
    <form class="form-horizontal">
      <div class="form-group">
        <label class="col-sm-2 control-label">Post title</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" placeholder="Post title">
        </div>
      </div>
      <div class="form-group">
        <label class="col-sm-2 control-label">Post body</label>
        <div class="col-sm-10">
          <textarea class="form-control" rows="5"></textarea>
        </div>
      </div>
      <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
          <button type="submit" class="btn btn-primary">Create</button>
        </div>
      </div>
    </form>
  </div>
</template>

好了,组件都已准备完毕,下面我们进入本文重点:把这些组件制作成动态组件。

当一个用户点击Manage Posts按钮,我们想让Vue渲染manage-posts组件。同样的,当点击Create Post按钮,渲染create-post组件,

实现动态组件我们需要<component>元素,我们把它当做动态组件的挂载点,然后在该元素上通过is属性指定我们需要渲染的组件。如此,我们可以通过下面的方式渲染manage-post组件:

<div class="container">
  <!-- render the currently active component/page here -->
  <component is="manage-posts"></component>
</div>

效果图如下:

然而,这种硬编码的方式似乎不是所谓地动态,我们目前仍然无法通过点击不同的按钮来展示不同的组件。

聪明的你也许已经想到了Vue的数据绑定。我们只需在data中定义一个名为currentView的属性,然后再对is属性进行数据绑定就行了,很简单:

new Vue({
  el: 'body',
  data: {
    currentView: 'manage-posts'
  }
})
<div class="container">
  <!-- render the currently active component/page here -->
  <component :is="currentView"></component>
</div>

最后,我们再给导航栏的两个按钮添加点击事件,这样用户每次点击即不同的按钮都会改变currentView的值,从而显示不同的组件:

...

<li role="presentation">
  <a href="#" @click="currentView='manage-posts'">Manage Posts</a>
</li>

<li role="presentation">
  <a href="#" @click="currentView='create-post'">Create Post</a>
</li>

...

完整代码

keep-alive

目前我们已经知道了如何创建动态组件,下面我们说说更加重要的keep-alive。

现在当我们每次点击按钮切换组件时,旧的组件就会被销毁而新的组件会被渲染出来。

这样一来就存在一个问题,旧的组件因为被销毁从而丢失了所有的状态,当重新渲染这个组件时不得不重新调用它所需要的API来获取已经发表的文章(这里我们假设是从服务器获取文章)。为了避免这个问题,我们可以使用keep-alive指令参数来把切出去的组件保留在内存中,以保留它的状态或避免重新渲染:

<div class="container">
  <!-- render the currently active component/page here -->
  <component :is="currentView" keep-alive></component>
</div>

在下面,我们可以验证被切出去的组件是否被保存在了内存中。我们可以在create-post组件中输入一些内容,接着切换组件,然后再切换回来。你会发现,我们输入的内容还在。

完整代码

如果你的组件需要调用很多API或者渲染时需要大量的数据,那么这个指令参数会很有用。

组件间的过渡

下面,我们在组件切换间添加一些过度效果。

在组件的挂载点上,增加transition属性,我们使用简单的淡入淡出的过渡效果。

<div class="container">
  <component :is="currentView" transition="fade" transition-mode="out-in"></component>
</div>

添加CSS过渡控制:

.fade-transition {
  transition: opacity 0.2s ease;
}

.fade-enter, .fade-leave {
  opacity: 0;
}

OK了,完整代码

你可能已经注意到了transition-mode="out-in"。这个属性告诉Vue,我们希望旧的组件先淡出,然后新的组件再淡入。否则的话,就会同时出现两个组件,一个淡出一个淡入,看上去相当别扭。

结束语

希望这篇教程能使你学会如何使用动态组件。这篇教程并不是为了说明动态组件可以替代vue-router,vue-router具有更多更有用的特性。对于一些简单的组件切换,我想动态组件可能会更合适。为了构建更好的SPA我觉得你应该学习一下vue-router。

pramper avatar Aug 20 '16 14:08 pramper