Skip to content

4.1 初识 Vue.js 3

Vue.js 3 是 Vue.js 的第 3 个版本。什么是 Vue.js?

Vue.js 是一款用于构建用户界面的 JavaScript 框架。它是基于标准 HTML、CSS 和 JavaScript 构建的,提供了一套声明式的、组件化的编程模型,可以帮助用户高效地开发用户界面。无论是简单的界面还是复杂的界面,使用 Vue.js 都可以完成。

由上述概念可以提取出两个关键词,分别为声明式和组件化。声明式和组件化是 Vue.js 的核心。Vue.js 使用最贴近 HTML、CSS 和 JavaScript 的语法,并且在此基础上扩展了一套简单的、数据与模板分离的响应式系统,使前端开发效率倍增。

与 jQuery 相比,Vue.js 几乎没有 DOM 操作,完全遵“循数据驱动视图”的思想。开发时只需关注如何定义数据和如何绑定数据,最终通过修改数据即可实现页面更新。另外,Vue.js 使用虚拟 DOM 这最大限度地避免了性能消耗,并且其模板语法与 HTML 相似度极高,学习成本很低。因此,Vue.js 受到很多开发者的欢迎。

Vue.js 3 集简单、好用、性能好、扩展性高等众多优点于一身,是现代框架的典型代表。

4.1.1 声明式渲染

上面介绍到,Vue 的核心之一是声明式渲染。那什么是声明式?

声明式是指我们可以像“声明变量”一样表示页面结构和绑定在页面上的数据。Vue 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。

举一个简单的例子,代码如下:

js
<div id="demo">{{ message }}</div>

上面代码中声明了一个 div 元素,并用双花括号包裹了一个数据 message 表示元素内容。默认情况下这只是个普通文本,如果要将其变成真实数据,还需要用 Vue3 提供的 createApp() 方法创建一个 Vue 实例:

js
import { createApp } from "vue";
createApp({
  data() {
    return {
      message: "hello world",
    };
  },
}).mount("#demo");

上述 Vue 实例中配置了数据并挂载了元素,将数据和 DOM 关联了起来,此时模版代码中的数据绑定就生效了,div 元素的内容变成了 “hello world”。通过这种方式,Vue 将视图和数据分离开来。

分离的目的是为了通过修改数据来更新视图。在 Vue 中,通常是定义一个方法来修改数据。我们在 Vue 实例的配置中添加一个 update() 方法:

js
createApp({
  data() {
    return {
      message: "hello world",
    };
  },
  methods: {
    update() {
      this.message = "你好全世界";
    },
  },
});

接着我们在模版上添加一个点击事件,触发上面定义的方法,如下:

vue
<div id="demo" @click="update">{{ message }}</div>

现在,我们点击文字 “hello world”,它会变成 “你好全世界”。如下:

从上面的结果可以看出,DOM 内容是随着数据的变化而变化的,这一切都归功于 Vue 实例将元素和数据绑定,从而形成了一套响应式系统。

4.1.2 在线运行代码

在学习 Vue 之初,为了快速了解 Vue 语法,避免搭建环境的繁琐,我们选择在线运行一个 Vue 项目。

在线运行项目是指在浏览器中编辑代码、实时预览运行结果,这种方式非常高效,并且有着和本地开发几乎一样的体验。一个比较好的在线代码平台是 codesandbox,它可以一分钟内运行一个 Vue3 的项目,具体步骤如下。

(1)打开 codesandbox 官网(https://codesandbox.io

如上图,点击按钮 Create Sandbox,进入创建项目的界面。

(2)在快速开始菜单中选择 Vue3,点击等待项目创建,如下图。

创建成功之后会出现下方的页面:

这个页面主体结构分为左、中、右三栏。左边是目录结构和安装的依赖,中间是代码编辑区域,右边是网页预览区域。在这个页面上,我们可以在左边区域添加/删除/切换文件、安装/卸载 npm 依赖包;在中间区域编辑某个文件的代码;代码保存之后,右边的预览区域会实时更新。

上面在 codesandbox 中创建了一个 Vue3 的基础工程项目,在这个项目中我们找到 components/HelloWorld.vue 这个文件。该文件是一个组件,在这里我们仅把它当作一个 Vue 实例。

HelloWorld.vue 文件中的代码可以分为三个区域:

  • <template></template>:模版区域
  • <script></script>:JavaScript 区域
  • <style></style>:样式区域

模版区域内是前面介绍的基于 HTML 的模版代码,在模版中声明式地绑定了数据,表示最终的页面结构;JavaScript 区域主要负责导出一个 Vue 实例配置,提供模版中需要的数据和方法等。样式区域自然是普通的 CSS 代码,用来修饰模版的样式。

这三个区域层次分明,可以帮助我们快速构建页面。我们将前面的代码放到这个文件中,如下:

vue
<!-- HelloWorld.vue -->
<template>
  <div id="demo" @click="update">{{ message }}</div>
</template>
<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      message: "hello world",
    };
  },
  methods: {
    update() {
      this.message = "你好全世界";
    },
  },
};
</script>
<style>
#demo {
  font-size: 16px;
}
</style>

现在,在 codesandbox 中的预览区域,点击文字 “hello world”,你会发现它变成了“你好世界”。

4.1.3 两种组件形式

在 HelloWorld.vue 中,我们导出一个 Vue 实例的方式是直接导出一个对象,并没有使用 createApp() 方法,这是正常的。为什么会这样?因为 HelloWorld.vue 是一个单文件组件。

什么是单文件组件?在了解这个概念前,我们先聊一下 Vue 的两种集成方式。

目前的前端项目大致可以分为以下两类:

  1. 普通项目
  2. 工程化项目

普通项目只包含 HTML、CSS、JavaScript 三种最基础的代码,是最原始的前端形态。而工程化项目则是以 Node.js 为根基,包含了编译、打包、构建等多个步骤,集成了 Webpack、TypeScript、Babel 等一系列的构建工具,最终将源码编译成可执行代码。

在普通项目中,集成 Vue 非常简单,只需要引入一个 vue.js 文件。引入之后初始化 Vue 示例,并在配置中注册组件,如下:

html
<!-- index.html -->
<body>
  <div id="demo">
    <h1>{{ message }}</h1>
    <test-com />
  </div>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script>
    const { createApp } = Vue;
    createApp({
      data() {
        return {
          message: "Hello Vue!",
        };
      },
      components: {
        TestCom: {
          template: "<h3>{{name}}</h3>",
          data() {
            return { name: "自定义组件" };
          },
        },
      },
    }).mount("#demo");
  </script>
</body>

上面代码中在 components 属性下配置了一个 TestCom 组件,在组件中配置了模版和数据,然后在页面中使用了该组件。使用方式是将组件名转换成小写,驼峰处用“-”连接,变成一个自定义元素 <test-com /> 添加在页面中,页面就会渲染出该组件的内容。

当组件复杂的时候,这种定义在一个对象内、用字符串表达模版的方式显然不够友好。

在工程化的项目中,因为有编译的能力,所以 Vue 选择了一种更友好的方案 —— 将组件提取到一个单独的文件中。该文件以 .vue 为后缀,因此被称为单文件组件,上面的 HelloWorld.vue 就是一个典型的在工程化项目中的单文件组件。

单文件组件有利于组件的拆分和单独管理,可以更灵活的组合应用。在工程化项目中,至少有以下三个文件必不可少:

  1. 入口文件:main.js
  2. 根组件:app.vue
  3. 页面文件:index.html

首先创建一个入口文件 main.js,用于创建 Vue 实例:

js
// main.js
import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

在入口文件中,导入的 App.vue 表示根组件,并且该组件是 createApp() 方法的参数。而在普通项目中。createApp() 方法的参数是一个组件 JSON 配置,这里为什么可以直接传一个组件呢?

事实上单文件组件和组件配置是一样的,它只是一种特殊的组件形态,最终还是会被编译成组件的 JSON 配置。

根组件 App.vue 的内容如下:

vue
<!-- app.vue -->
<template>
  <div id="app">
    <header>我的应用标题</header>
    <HelloWorld msg="Hello Vue 3 in CodeSandbox!" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
  name: "App",
  components: {
    HelloWorld,
  },
};
</script>

根组件中可以导入其他组件,上面代码中导入了 HelloWorld 组件,这是单文件组件的一大优势 —— 通过组件间的互相引用和嵌套,可以很轻松的组成了一个大型的完整的应用。

提示:组件定义时,组件名一般都是大写。在 Vue 模版中为了保持格式统一,支持对组件名称自动转换为小写,多个大写单词之间用符合 “-” 分割。以下两种写法在模版中都是一样的:

vue
<HelloWorld msg="Hello Vue 3 in CodeSandbox!" />
<hello-world msg="Hello Vue 3 in CodeSandbox!" />

在入口文件中创建的 Vue 实例最终要挂载到页面文件 index.html 的元素上才能被显示出来。页面文件如下:

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>首页</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

现在再看前面我们在 codesandbox 中创建的项目,目录结构正好对应上面的三个文件,是不是恍然大悟了呢?