Vue.js 学习笔记之七:使用现有组件

在之前的五个实验中,我们所演示的基本都是如何构建自定义组件的方法,但在具体开发实践中,并非项目中所有的组件都是需要程序员们自己动手来创建的。毕竟在程序设计领域,“不要重复发明轮子”也是一项理应受到所有程序员遵守的基本原则。换而言之,在亲自动手创建一个组件之前,程序员们理应先确认一下 Vue.js 框架的内置组件库,以及当前流行的第三方组件库中是否已经提供了类似功能的组件。如果有的话,就直接拿来使用即可,不必再去自定义一个功能重复的组件了。遵守这一基本原则不仅可以避免重复劳动,提高程序员们的项目开发效率,而且由于这些组件库提供的组件通常都经历过更严格、更系统性的测试和优化,所以直接使用它们来完成相关任务也有助于改善程序本身的性能和安全性。

使用内置组件

根据 Vue.js 框架的官方文档,该框架主要为用户提供了以下五个内置组件,让我们先来简单介绍这些组件的功能:

  • component组件:该组件主要用于在用户界面中进行界面元素(包括自定义标签)的动态切换。
  • transition组件:该组件主要用于定义在用户界面中切换界面元素(包括自定义标签)时的动画效果。
  • transition-group组件:该组件主要用于定义在用户界面中分组切换多个界面元素(包括自定义标签)时的动画效果。
  • keep-alive组件:该组件主要用于在组件切换的过程中缓存不活动的组件对象,以便该组件被切换回来时能维持之前的状态。
  • slot组件:该组件主要用于在自定义组件模板预留其他组件标签或 HTML 标准标签可以插入的插槽位置。

细心的读者可能已经发现了,上述组件除了slot组件是用于在自定义组件时预留插槽之外(我们在之前的实验中已经演示过了该组件的使用方法),其他四个组件都与用户界面中界面元素的切换有关。这让人想到通过一个让用户在登录界面和注册界面之间来回切换的实验来演示这些内置组件的使用方法。下面先从component组件开始,让我们执行以下步骤来开始构建本章的第六个实验:

  1. 首先在code/otherTest目录中再创建一个名为component_users的目录,并在该目录下创建publicsrc这两个子目录。

  2. 由于component_users实验所需要的依赖项以及目录结构都与component_wp实验相同,为了免除不必要的工作量,节省花费在该实验项目配置工作上的时间,我们可以直接将component_wp目录下的package.jsonwebpack.config.js这两个分别与依赖项与项目打包相关的配置文件复制到component_users目录下(并根据需要稍作修改),然后在component_users目录下执行npm install命令来安装已经配置在package.json文件中的项目依赖项。

  3. src目录下创建一个名为userLogin.vue文件,并在其中创建用于定义用户登录界面的组件。具体代码如下:

     <template>
         <div id="tab-login">
             <table>
                 <tr>
                     <td>用户名:</td>
                     <td><input type="text" v-model="userName"></td>
                 </tr>
                 <tr>
                     <td>密  码:</td>
                     <td><input type="password" v-model="password"></td>
                 </tr>
                 <tr>
                     <td><input type="button" value="登录" @click="login"></td>
                     <td><input type="button" value="重置" @click="reset"></td>
                 </tr>
             </table>
         </div>
     </template>
     <script>
         export default {
             name: "tab-login",
             props : ['value'],
             data: function() {
                 return {
                     userName: '',
                     password: ''
                 };
             },
             methods: {
                 login: function() {
                     if(this.userName !== '' && this.password !== '') {
                         if(this.userName === 'owlman' && this.password === '0000') {
                             this.$emit('input', true);
                         } else {
                             window.alert('用户名或密码错误!');
                             
                         }
                     } else {
                         window.alert('用户名与密码都不能为空!');
    
                     }
                 },
                 reset: function() {
                     this.userName = '';
                     this.password = '';
                 }
             }
     };
     </script>
    
  4. src目录下创建一个名为userSignUp.vue文件,并在其中创建用于定义用户注册界面的组件。具体代码如下:

     <template>
         <div id="tab-sign">
             <table>
                 <tr>
                     <td>请输入用户名:</td>
                     <td><input type="text" v-model="userName"></td>
                 </tr>
                 <tr>
                     <td>请设置密码:</td>
                     <td><input type="password" v-model="password"></td>
                 </tr>
                 <tr>
                     <td>请重复密码:</td>
                     <td><input type="password" v-model="rePassword"></td>
                 </tr>
                 <tr>
                     <td><input type="button" value="注册" @click="signUp"></td>
                     <td><input type="button" value="重置" @click="reset"></td>
                 </tr>
             </table>
         </div>
     </template>
     <script>
         export default {
             name: "tab-sign",
             data() {
                 return {
                     userName: '',
                     password: '',
                     rePassword: ''
                 };
             },
             methods: {
                 signUp: function() {
                     if(this.userName !== '' &&
                     this.password !== '' &&
                     this.rePassword !== '') {
                         if(this.password === this.rePassword) {
                             window.alert('用户注册');
                         } else {
                             window.alert('你两次输入的密码不一致!');
                         }
                     } else {
                         window.alert('请正确填写注册信息!');
                     }
    
                 },
                 reset: function() {
                     this.userName = '';
                     this.password = '';
                     this.rePassword = '';
                 }
             }
         };
     </script>
    
  5. src目录下创建main.js文件,并在实现 Vue 对象时将上面两个新建的组件注册成局部组件,具体代码如下:

     import Vue from 'vue';
     import userLogin from './userLogin.vue';
     import userSignUp from './userSignUp.vue';
    
     new Vue({
         el: '#app',
         data: {
             componentId: 'login',
             isLogin: false
         },
         components: {
             login: userLogin,
             signup : userSignUp
         }
     })
    
  6. src目录下创建index.htm文件,并在设计应用程序的用户界面时使用<component>标签指定首先要载入的组件,并用<input>标签在该界面中设置两个用于切换组件的按钮元素,具体代码如下:

     <!DOCTYPE html>
     <html lang="zh-cn">
         <head>
             <meta charset="UTF-8">
             <style>
                 body {
                     background: black;
                     color: floralwhite;
                 }
                 .box {
                 width: 400px;
                 height: 300px;
                 border-radius: 14px;
                 padding: 14px;
                 color: black;
                 background: floralwhite;
             }
             </style>
             <title>Vue 组件实验(6):使用动态组件</title>
         </head>
         <body>
             <div id="app" class="box">
                 <h1>用户登录</h1>
                 <div v-show="!isLogin">
                     <input type="button" value="注册新用户"
                         @click="componentId='signup'">
                     <input type="button" value="用户登录" 
                         @click="componentId='login'">
                     <component :is="componentId" v-model="isLogin"></component>
                 </div>
                 <div v-show="isLogin">登录成功</div>
             </div>
         </body>
     </html>
    
  7. 用浏览器访问public目录下的index.html文件,就可以看到最后的结果了,如下图所示:

    用户的登录与注册

在上述代码中,读者可以看到我们在使用component组件时主要设置了两个属性。首先是is属性,这是使用component组件必须要设置的属性。该属性应该是一个字符串类型的值,主要用于在一组要被切换的组件中指定当前被激活的组件。在这里,我们先用v-bind指令将其绑定到了 Vue 对象中一个名为componentIddata成员上,然后再通过两个按钮元素的单击事件来改变该属性的值,从而实现了在userLoinuserSignUp这两个组件之间的切换。接下来是用v-model指令双向绑定的 Vue 对象中另一个名为isLogindata成员,这不是使用component组件必须要设置的数学,我们绑定该数据是为了记录用户的登录状态,并以此来决定应用程序是否需要在用户界面中显示与用户登录与注册功能相关的界面元素。

实验进行到这一步,我们事实上已经在应用程序的用户界面中初步实现了一个与用户登录与注册功能相关的模块,但这个模块还存在着一个小问题亟待解决,那就是组件在被切换时已经获得的用户输入会被丢失。也就是说,如果我们在用户注册界面中输入信息的过程中不小心用鼠标单击了“用户登录”按钮元素,因此切换到了用户登录界面,然后再切换回去时之前输入的信息就会全部丢失,这在用户注册时需要输入输入较多信息的应用程序中可能会带来较差的用户体验,在 Vue.js 框架中,我们可以使用keep-alive组件来解决这个问题,该组件的使用方法非常简单,只需要将上面的component组件的标签放到keep-alive组件的标签内部即可,像这样:

<keep-alive>
    <component :is="componentId" v-model="isLogin"></component>
</keep-alive>

除此之外,程序员们还可以通过在transition组件在界面元素切换过程中加入一些自己想要的过渡效果。下面是我们在使用transition组件可以设置的主要属性:

  • name属性:该属性是一个字符串类型的值,主要用于自动生成界面元素在切换过程中过渡样式的 CSS 类名。例如当我们将name属性的值设置为'usersModule'时,就等于自动创建了.usersModule-enter.usersModule-enter-active等一系列样式的 CSS 类名。
  • appear属性:该属性是一个布尔类型的值,主要用于指定是否要在用户界面初始化时就使用过渡样式。默认值为false
  • css属性:该属性是一个布尔类型的值,主要用于指定是否要使用 CSS 样式类来定义过渡效果。默认值为true
  • type属性:该属性是一个字符串类型的值,主要用于指定过渡事件类型,侦听过渡何时结束。有效值包括transitionanimation
  • mode属性:该属性是一个字符串类型的值,主要用于控制界面元素退出/进入过渡的时间序列。有效值包括out-inin-out

通常情况下,我们只需依靠 CSS 样式就可以实现一些简单够用的过渡效果了。但当transition组件的css属性值为false或需要实现更复杂的过渡效果时,就需要通过定义一些由transition组件预设的事件钩子函数来定义一些需要通过 JavaScript 代码来执行的操作,下面是我们在使用transition组件时可以定义的主要事件钩子函数:

  • before-enter函数:该钩子函数会在相关界面元素进入之前用户界面时被调用。
  • before-leave函数:该钩子函数会在相关界面元素退出之前用户界面时被调用。
  • enter函数:该钩子函数会在相关界面元素进入用户界面时被调用。
  • leave函数:该钩子函数会在相关界面元素退出用户界面时被调用。
  • after-enter函数:该钩子函数会在相关界面元素进入之后用户界面时被调用。
  • after-leave函数:该钩子函数会在相关界面元素退出之后用户界面时被调用。

这里需要说明的是,以上列出的只是一些常用的属性和函数,并非是transition组件提供的所有属性和事件钩子函数,读者如果阅读关于该组件更全面的参考资料,还请自行去查阅 Vue.js 的官方文档[^3]。下面,我们来简单示范一下transition组件的基本使用方式。在之前的第六个实验中,如果想在userLoinuserSignUp这两个组件的切换过程中加入一些过渡效果,可以将要切换的组件放到transition组件标签内部,并根据需要设置该组件的属性,例如像这样:

<transition name='usersModule' mode='out-in'>                
    <keep-alive>
        <component :is="componentId" v-model="isLogin"></component>
    </keep-alive>
</transition>

在这里,我们先将transition组件的mode属性设置成了out-in,使得界面元素的切换顺序变成了先退出再进入,然后在将其name属性设置成了userModule。正如之前所说,name属性的设置会自动创建一系列用于定义过渡效果 CSS 类名。下面,我们只需要根据项目的需要在index.htm文件的<style>标签或其外链的 CSS 文件中定义一下其中的某个类,例如像这样:

@keyframes usersAni {
    0% {
        transform: scale(0);
    }
    50% {
        transform: scale(1.5);
    }
    100% {
        transform: scale(1);
    }
}
.usersModule-leave-active {
    animation: usersAni .5s;
}

如你所见,我们在上述代码中定义了一个缩小放大效果的简单过场动画,然后在名为usersModule-leave-active的 CSS 类中使用了它。这样一来,读者就可以在userLoinuserSignUp这两个组件的切换过程中看到类似放大镜扫过的过渡效果了。当然,当前这个实验中演示的只是最简单的过渡效果设置。在后续具体的项目实践中,我们将陆续演示如何使用transition组件和transition-group组件设置出更复杂、更具实用功能的过渡效果。

引入外部组件

由于 Vue.js 是一个开放性的前端框架,所以这些年在开源社区已经累积了不少既美观又好用的第三方组件库。在实际项目中,程序员们更多时候会选择从外部引入第三方的组件来构建应用程序的用户界面。下面,我们就以 Element 组件库为例来介绍一下如何在一个基于 Vue.js 框架的前端项目中引入第三方组件库。

  1. 先来创建本章第七个实验项目所在的目录,即在code/otherTest目录中再创建一个名为hello_element的目录,并在该目录下创建publicsrc这两个子目录。

  2. 由于hello_element实验所需要的依赖项以及目录结构都与component_wp实验相同,为了免除不必要的工作量,节省花费在该实验项目配置工作上的时间,我们可以直接将component_wp目录下的package.jsonwebpack.config.js这两个分别与依赖项与项目打包相关的配置文件复制到hello_element目录下(并根据需要稍作修改),然后在hello_element目录下执行npm install命令来安装已经配置在package.json文件中的项目依赖项。

  3. hello_element目录下执行npm install --save element-ui命令将 Element 组件库安装到当前实验项目中。

  4. src目录下创建main.js文件。在该文件中,我们会先使用import语句分别导入 Vue.js 框架与 Element 组件库,接着再通过调用Vue.use()方法将 Element 组件库加载到 Vue.js 框架中。然后就可以照常创建 Vue 对象了,具体代码如下:

     import Vue from 'vue';
     import ElementUI from 'element-ui';
    
     Vue.use(ElementUI);
    
     new Vue({
         el: '#app',
         data : {
             title: 'Element 组件库',
             message : '一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库。'
         },
         methods : {
             goDocument : function() {
                 window.open('//element.faas.ele.me/#/zh-CN', '_blank');
             }
         }
     });
    
  5. src目录下创建index.htm文件,并在设计应用程序的用户界面时使用 Element 组件库中的组件标签。至于该组件库中有多少可用的组件以及这些组件所对应的标签,读者可以自行查阅其官方文档[^4]。我们在这里只是简单示范了Card组件和Button组件的使用方法,为的是证明组件库已经被成功引入到项目中,具体代码如下:

     <!DOCTYPE html>
     <html lang="zh-cn">
         <head>
             <meta charset="UTF-8">
             <!-- 在正式使用 Element 组件之前,请务必要记得加载其样式文件。 -->
             <link rel="stylesheet"
                 href="../node_modules/element-ui/lib/theme-chalk/index.css">
             <title>Vue 组件实验(7):引入第三方组件库</title>
         </head>
         <body>
             <div id="app">
                 <h1>引入第三方组件库</h1>
                 <el-card shadow="always">
                     <h2> {{ title }} </h2>
                     <p> {{ message }} </p>
                     <el-button type="info" @click='goDocument'>
                         查看官方文档
                     </el-button>
                 </el-card>
             </div>
         </body>
     </html>
    
  6. 用浏览器访问public目录下的index.html文件,就可以看到最后的结果了,如下图所示:

    引入第三方组件

需要特别说明的是,我们在这里只是简单地介绍了如何在一个基于 Vue.js 框架的前端项目中引入第三方组件库。至于在实际生产环境中是否真的就使用 Element 组件库,还是选择别的组件库,还是要根据项目的实际需求和这些组件库的具体特性来做决定。在后续具体的项目实践中,我们将陆续演示如何使用这些第三方组件库设计出更复杂、更符合实际需求的用户界面。