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 状态之间的关系。
举一个简单的例子,代码如下:
<div id="demo">{{ message }}</div>
上面代码中声明了一个 div 元素,并用双花括号包裹了一个数据 message 表示元素内容。默认情况下这只是个普通文本,如果要将其变成真实数据,还需要用 Vue3 提供的 createApp()
方法创建一个 Vue 实例:
import { createApp } from "vue";
createApp({
data() {
return {
message: "hello world",
};
},
}).mount("#demo");
上述 Vue 实例中配置了数据并挂载了元素,将数据和 DOM 关联了起来,此时模版代码中的数据绑定就生效了,div 元素的内容变成了 “hello world”。通过这种方式,Vue 将视图和数据分离开来。
分离的目的是为了通过修改数据来更新视图。在 Vue 中,通常是定义一个方法来修改数据。我们在 Vue 实例的配置中添加一个 update() 方法:
createApp({
data() {
return {
message: "hello world",
};
},
methods: {
update() {
this.message = "你好全世界";
},
},
});
接着我们在模版上添加一个点击事件,触发上面定义的方法,如下:
<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 代码,用来修饰模版的样式。
这三个区域层次分明,可以帮助我们快速构建页面。我们将前面的代码放到这个文件中,如下:
<!-- 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 的两种集成方式。
目前的前端项目大致可以分为以下两类:
普通项目
。工程化项目
。
普通项目只包含 HTML、CSS、JavaScript 三种最基础的代码,是最原始的前端形态。而工程化项目则是以 Node.js 为根基,包含了编译、打包、构建等多个步骤,集成了 Webpack、TypeScript、Babel 等一系列的构建工具,最终将源码编译成可执行代码。
在普通项目中,集成 Vue 非常简单,只需要引入一个 vue.js 文件。引入之后初始化 Vue 示例,并在配置中注册组件,如下:
<!-- 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 就是一个典型的在工程化项目中的单文件组件。
单文件组件有利于组件的拆分和单独管理,可以更灵活的组合应用。在工程化项目中,至少有以下三个文件必不可少:
- 入口文件:
main.js
- 根组件:
app.vue
- 页面文件:
index.html
首先创建一个入口文件 main.js,用于创建 Vue 实例:
// main.js
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
在入口文件中,导入的 App.vue 表示根组件,并且该组件是 createApp() 方法的参数。而在普通项目中。createApp() 方法的参数是一个组件 JSON 配置,这里为什么可以直接传一个组件呢?
事实上单文件组件和组件配置是一样的,它只是一种特殊的组件形态,最终还是会被编译成组件的 JSON 配置。
根组件 App.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 模版中为了保持格式统一,支持对组件名称自动转换为小写,多个大写单词之间用符合 “-” 分割。以下两种写法在模版中都是一样的:
<HelloWorld msg="Hello Vue 3 in CodeSandbox!" />
<hello-world msg="Hello Vue 3 in CodeSandbox!" />
在入口文件中创建的 Vue 实例最终要挂载到页面文件 index.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 中创建的项目,目录结构正好对应上面的三个文件,是不是恍然大悟了呢?