本文记录 Vue3 的学习过程,内容为环境配置、概念、整体布局设计。
Vue 中文官网:Vue.js。
Vue.js 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助开发者高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。Vue 的设计非常注重灵活性和“可以被逐步集成”这个特点。根据你的需求场景,你可以用不同的方式使用Vue。
Vue 与 React 的区别主要在于:
- React 的思路是 HTML in JavaScript,也可以说是 All in JavaScript,通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS。
- Vue 是把 HTML、CSS、JS 组合到一起,用各自的处理方式,Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。
- React 整体是函数式的思想,在 React 中是单向数据流,推崇结合
immutable
来实现数据不可变。 - Vue 的思想是响应式的,也就是基于数据可变的,通过对每一个属性建立
Watcher
来监听,当属性变化的时候,响应式地更新对应的虚拟 DOM。
总的来说,React 的性能优化需要手动去做,而 Vue 的性能优化是自动的,但是 Vue 的响应式机制也有问题,就是当 state
特别多的时候,Watcher
会很多,会导致卡顿。所以大型应用(状态特别多的)一般用 React,更加可控。而考虑易用性方面,Vue 是更容易上手的,对于项目来说新人更容易接手。
1. 环境配置
首先需要安装 Node.js:NodeJS 的安装及配置。
打开 PowerShell,安装 @vue/cli
:
1 | npm i -g @vue/cli |
Vue 相比于 React 的其中一个好处是默认提供了一个图形化的项目管理界面,在想要创建项目的文件夹下以管理员身份打开终端输入以下命令:
1 | vue ui |
然后我们创建一个名为 my_space
的项目,包管理器选择 npm
,然后选上无新手指引的脚手架项目(Scaffold project without beginner instructions),预设选择 Vue3,然后创建项目。
项目创建好后在左侧能够看到导航栏,进入插件页面(Plugins)安装以下插件,其中 @vue/cli-plugin-router
用于多页面路由,@vue/cli-plugin-vuex
类似于 React 中的 Redux,可以让我们在多个组件之间维护同一个数据:
1 | @vue/cli-plugin-router |
然后我们在依赖页面(Dependencies)安装 Bootstrap。
最后在任务页面(Tasks)的 serve
选项卡中可以运行项目,运行后在输出(Output)中可以看到网站链接:http://localhost:8080/
,访问该链接即可看到 Vue 的初始化页面。
我们用 VS Code 打开项目的根目录,源代码位于 src
目录下,其中的 views
目录类似于 Django 中的 Views,每一个页面是一个 View;router
目录是路由,打开可以看到默认有两个路由分别是 /
和 /about
;components
目录用于存放各种组件(views
也能存放组件,根据个人习惯决定);App.vue
为根组件,整个项目的入口在 main.js
文件中。
仔细看一下页面的链接会发现其中有一个 #
,如果想去掉可以将 router
目录下 index.js
文件中的 createWebHashHistory
修改为 createWebHistory
(有两处需要修改)。
在 main.js
文件中可以看到以下代码:
1 | createApp(App).use(router).use(store).mount('#app') |
其中创建了我们的根组件 App
,router
就表示路由,store
即 vuex
,然后将其挂载到 #app
标签上,该标签可以在 public/index.html
中看到。
2. 使用 Vue 开发项目的基本概念
每一个 .vue
文件都会由三个部分组成:HTML、CSS、JS。其中 CSS 的标签可以加一个属性 scoped
,这样不同组件之间的 CSS 选择器就不会相互影响到了:
1 | <style scoped> |
我们的每个页面中都可能由多个组件组成,每个组件是一个 .vue
文件,可以用以下的方式引入 HelloWorld
组件,并传递 msg
属性给该组件:
1 | <template> |
HelloWorld
组件需要 export
出去:
1 | <script> |
其中 props
中的属性可以在创建该组件的父组件中传递进来。
现在我们来具体了解一下 <script>
中的 export default
的参数:
name
:组件的名称。components
:存储<template>
中用到的所有组件。props
:存储父组件传递给子组件的数据。watch()
:当某个数据发生变化时触发。computed
:动态计算某个数据。setup(props, context)
:初始化变量、函数。ref
:定义变量,可以用.value
属性取值或者重新赋值,效率稍微比reactive
低一些。reactive
:定义对象,不可重新赋值。props
:存储父组件传递过来的数据。context.emit()
:触发父组件绑定的函数。
然后是 <template>
中的内容:
<slot></slot>
:存放父组件传过来的children
。v-on:click
或@click
属性:绑定事件。v-if
、v-else
、v-else-if
属性:判断。v-for
属性:循环,注意需要用:key
给循环的每个元素绑定唯一的key
。v-bind:
或:
:绑定属性。
<style>
部分需要注意的就是添加 scope
属性后,不同组件间的 CSS 不会相互影响。
最后是第三方组件:
vue-router
:实现路由功能。vuex
:存储全局状态,全局唯一。state
:存储所有数据,可以用modules
属性划分成若干模块。getters
:根据state
中的值计算新的值。mutations
:所有对state
的修改操作都需要定义在这里,不支持异步,可以通过$store.commit()
触发。actions
:定义对state
的复杂修改操作,例如使用 Ajax 向后端请求数据后再做修改操作,支持异步,可以通过$store.dispatch()
触发。注意不能直接修改state
,只能通过mutations
修改state
,actions
中函数的第一个参数为context
,通过context.commit()
可以调用mutations
中的操作。modules
:定义state
的子模块。
这些概念先不用背,之后用到时再回来理解什么意思即可。
3. 导航栏
我们将整个页面分为导航栏(NavBar)和内容部分(Content),导航栏在每个页面都是固定不变的,变化的只有内容部分。我们将要实现首页、用户列表、用户动态、登录、注册以及404页面,每个页面我们都可以实现为一个组件。
在根 JS 文件 main.js
中引入 Bootstrap:
1 | import { createApp } from 'vue' |
这时候会报错,提示我们没有找到模块 @popperjs/core
,这时我们需要去项目管理页面的依赖页面中安装 @popperjs/core
依赖。
现在先把 HelloWorld.vue
删掉,然后把 HomeView.vue
中关于 HelloWorld
组件的内容删去,在 components
目录下创建 NavBar.vue
,我们现在先不实现路由功能,直接去 Bootstrap 官网找一个导航栏复制过来:
1 | <template> |
然后我们在 App.vue
中把导航栏组件添加进来,并删去原本的内容:
1 | <template> |
4. 页面创建
首先我们用 Bootstrap 的 Card
先实现一个卡片组件 Card.vue
:
1 | <template> |
注意,如果发现报错:Component name "Card" should always be multi-word vue/multi-word-component-names
,说明文件名没有驼峰命名,可以在 package.json
文件的 rules
中添加一行代码,然后停止项目重新启动即可:
1 | "vue/multi-word-component-names": "off" |
然后我们在 HomeView
中即可使用这个组件:
1 | <template> |
可以看到 Card
中使用 {{ msg }}
在 HTML 标签中获取 prop
中 title
的值,该值由父组件 HomeView
传入。<slot></slot>
类似 React 中的 this.props.children
。
现在我们可以根据 HomeView
创建其他页面:UserListView
、UserNewsView
、LoginView
、RegisterView
、NotFoundView
。
创建好页面后我们需要实现路由,即根据地址来显示对应的组件。在 src/router/index.js
文件中修改:
1 | import { createRouter, createWebHistory } from "vue-router"; |
最后我们在导航栏 NavBar
中实现地址的跳转,如果直接在 <a>
标签上写地址那么为后端渲染,即每次切换页面都需要访问一遍后端请求数据,我们可以用 <router-link>
实现前端渲染:
1 | <template> |
其中 :to
表示绑定 to
属性,参数是一个对象,其中的 name
属性表示名称,即之前在 router
中定义的 name
。