Vue.js 学习笔记之四:Vue 组件基础

到目前为止,这个系列的笔记所展示的都是一些极为简单的单页面 Web 应用程序,并且页面上通常只有几个简单的交互元素。但在实际生产环境中,Web 应用程序的用户界面往往是由多个复杂的页面共同组成的。这时候,我们就需要开始注意代码的可复用性了,针对这个问题,Vue.js 框架提出的解决方案就是先将用户界面上的元素按照不同的功能划分成一个个独立的组件,例如导航栏、公告栏、数据表格、用户注册表单、用户登录界面等。这样一来,我们在之后的工作中就可以像玩乐高玩具一样,根据需要将这些组件组合成各种具体的应用程序了。总而言之,组件系统是我们在学习 Vue.js 框架中必须要掌握的一个重要概念。下面,这篇笔记将通过编写一系列实验示例来体验一下在 Vue.js 框架中构建和使用组件的基本方法。

在所有实验开始之前,我需要先在code目录中创建一个名为00_test的目录,以便用于存放接下来的一系列实验项目,由于这些项目只能用于体验 Vue 组件的构建与使用方法,并没有实际的应用功能,所以我给了它00这个编号。那么,下面就来开始第一个实验吧!为此,我需要继续在code/00_test目录中再创建一个名为component_1的实验目录,并在该目录下执行npm install vue命令来安装 Vue.js 框架。最后,我只需在code/00_test/component_1目录下创建一个名为index.htm的文件,并输入如下代码:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA  -Compatible" content="ie=edge">
    <title>学习 vue 组件实验(1):组件注册</title>
`</head>
<body>
    <div id="app">
        <say-hello :who="who"></say-hello>
        <welcome-you :who="who"></welcome-you>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        // 全局组件注册
        Vue.component('say-hello', {
            template: `<h1>你好, {{ you }}!</h1>`,
            props: ['who'],
            data: function() {
                return {
                    you: this.who
                };
            }
        });

        const app = new Vue({
            el: '#app',
            // 局部组件注册
            components: {
                'welcome-you': {
                    template: `<h2>欢迎你, {{ you }}!</h2>`,
                    props: ['who'],
                    data: function() {
                        return {
                            you: this.who
                        };
                    }
                }
            },
            data: {
                who: 'vue'
            }
        });
    </script>
</body>
</html>

在上述实验中,我用两种不同的方式分别创建并注册了say-hellowelcome-you两个组件。接下来就借由这两个组件来介绍一下这两种组件的使用。首先是say-hello组件,该组件是通过调用Vue.component()方法来创建并注册到应用程序中的,使用该方法创建的组件通常被称之为”全局组件”,我们在调用它的时候需要提供两个参数:

  • 第一个参数应该是一个字符串对象,用于指定组件的名称,该名称也是我们要在 HTML 文档中使用的自定义标签元素,而由于 HTML 代码是大小写不敏感的,所以我个人会建议大家在给组件起名字的时候应该尽量一律使用小写字母,单词之间可以使用-这样分隔符进行区隔。

  • 第二个参数应该是一个 JavaScript 对象,用于设置组件的各项具体参数。这里定义了以下三项最基本参数:

    • template:该参数是个字符串对象,用于指定该组件的 HTML 模版代码,需要注意的是,这段代码说对应的 DOM 对象必须有且只能有一个根节点。而这个对象在最终的 HTML 文档中将会由该组件所对应自定义标签所代表,在这里就是<say-hello>
    • props:该参数是一个字符串数组,该数组中的每个元素都是该组件所对应的自定义标签的一个属性,该组件的用户可以通过v-bind指令将该属性绑定到某一数据上,以便将数据传到组件内部。例如在这里,我在<say-hello>标签中就用v-bind指令将该标签的who属性绑定到了 Vue 实例对象的who数据上,并将其传进say-hello组件中。
    • data:该参数是一个函数,用于设置组件自身的数据,例如这里的you,我将从调用者那里获取的who数据赋值给了它。对于后者,我们可以用this引用来获取。

    当然了,除了上面三个基本参数之外,我们还可以为组件设置更多参数,例如自定义事件及其处理函数等,这些我将会在后续的程序编写体验中展示。

下面,我们再来看welcome-you组件的构建。如你所见,该组件是在 vue 实例的components成员中构建并注册到应用程序中的,使用该方法创建的组件通常被称之为”局部组件”(它与全局组件的区别是,全局组件会在程序运行时全部加载,而局部组件只会在被实际用到时加载) 。该components成员的值也是一个 JSON 格式的数据对象,该数据对象中的每一个成员都是一个局部组件,这些组件采用键/值对的方式来定义,键对应的是组件的名称,值对应的是组件参数的设置。当然了,由于局部组件的命名规则与具体参数的设置方法都与全局对象一致,这里就不再重复说明了。

需要注意的是,第一个实验项目的编写方式将 HTML 代码、Vue 实例的构建代码以及组件的构建代码糅合在了一起,这对于提高代码的可复用性这个目的来说,显然是不行的。要想解决这个问题,我们可以利用 ES6 规范新增的模块规则将这三部分代码隔离开来。为了体验这种用法,我继续开始了第二个实验。具体做法就是在code/00_test目录中再创建一个名为component_2的实验目录,并在该目录下执行npm install vue命令来安装 Vue.js 框架。最后,我只需在code/00_test/component_2目录下创建一个名为index.htm的文件,并输入如下代码:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="module" src="./main.js"></script>
    <title>学习 vue 组件实验(2):以 ES6 模块的方式注册组件</title>
</head>
<body>
    <div id="app">
        <say-hello :who="who"></say-hello>
    </div>
</body>
</html>

在上述 HTML 代码中,我们在照常引入 vue.js 框架之后,使用模块的方式引入了main.js脚本文件,最好在<div id="app">标签中使用了后面将要定义的组件所对应的自定义标签。接下来,我只需要在相同的目录下创建一个名为main.js的 JavaScript 脚本文件,并在其中输入如下代码:

// import Vue from './node_modules/vue/dist/vue.js';
import sayhello from './sayhello.js';

const app = new Vue({
    el: '#app',
    components: {
        'say-hello': sayhello
    },
    data: {
        who:'vue'
    }
});

在上述 JavaScript 代码中,我首先使用了 ES6 新增的import-from语句导入了后续要在sayhello.js文件中构建的组件,然后在构建 Vue 实例时将其注册成了局部组件。最后,我只需在同一目录下再创建这个sayhello.js脚本文件,并在其中输入如下代码:

const tpl = `
    <div>
        <h1>你好, {{ you }}!</h1>
        <input type="text" v-model="you" />
    </div>
`;

const sayhello = {
    template: tpl,
    props : ['who'],
    data : function() {
        return {
            you: this.who
        }
    }
};

export default sayhello;

在这部分代码中,我先定义了一个局部组件,然后再使用 ES6 新增的export default语句将其导出为模块。当然了,考虑到各种 Web 浏览器对 ES6 规范的实际支持情况,以及 Vue.js 框架本身使用的是 CommonJS 模块规范,所以上述实验依然可能不是编写 Vue.js 项目的最佳方式,其中可能还需要配置 babel 和 webpack 这样的转译和构建工具来辅助。当然了,如果大家不想陷入如此复杂的配置,那使用 Vue 官方提供的 vue-cli 脚手架工具是一个不错的选择,在下一篇笔记中,我就来记录如何使用这个工具来构建具体的 vue 应用程序。