Vue3 + Element3 学习过程简单记录
Vue3 + Element3 学习过程简单记录
两周前,师兄要我完成一个前端的任务。因此我选择了较为熟悉的前端框架 Vue3 和配套的 UI 框架 ElementPlus,原型设计工具是 Figma。我最终实现的界面如下所示:
1. 简介
1.1 框架选择原因
(1) 选择 Vue3 的原因有如下几点:
- 方便搭建。依照官方给出的安装教程,
- 上手简单。只需要会一些 JavaScript 等前端开发的基础知识。
- 轻量级。越简单越好,这是我们的项目需求使然。我们的目标是创建一个简单的前端搜索和展示页面,不需要进行页面之间的跳转。虽然像 Vue 这样的框架构建的网页本质上就是单页面,但实际上对于复杂项目来说,Vue 也需要进行许多代码的编写。
在可视化前端中,除了像 Vue 和 Angular 这样的前端框架之外,还有 D3 这种小巧的 js 库。由于我对 D3 不熟悉,所以我最终还是选择了 Vue。
由于 Vue3 相对 Vue2 来说更加新,所以 Vue3 的教程会相对来说少一些,面对一些 Error 什么的,还是不好弄。
(2) 选择 ElementPlus 的原因有如下几点:
- 和 Vue3 配套。
- 有许多方便使用的组件。
- 风格统一。
当然,Element 存在许多便捷的组件,这也意味着它的灵活性大大降低。我在开发的过程中,花费了 60% 的时间调整组件带给我的不灵活之处。
1.2 个人习惯
英文报错搜谷歌,谷歌搜不到就搜 ElementPlus 在 Github 的 issues。除了本次项目我尝试使用 issues 来进行调试外,在使用很多其他开源项目时,如果我们碰到 BUG 或者一些安装方面的问题,我们都可以尝试去项目的 issues 部分进行查询或者直接提问。一般而言,生命力比较旺盛的开源项目都会有工作人员进行维护。在这里就不吐槽那些为了发论文所以开放项目地址但从不回应 issues 的人。
代码的基本写法搜必应,必应搜不到就转换成英文搜谷歌。鉴于我很长时间没有使用过 JavaScript 了,很多基本的数据结构的增删改查我不会使用,连循环都不会。中文版本的菜鸟教程和 w3cschool 以及少量的 CSDN 就可以满足我的需求。虽然我一直骂 CSDN 坑人,但我目前搜中文编程的一些基础资料还是会偶尔参考一下 CSDN。
1.3 前端原型
我师兄使用 Figma 画的原型。我师兄是个大佬,但是他很谦虚,认为自己是个小虾米。我根据他画的前端原型来进行前端的实现。在代码实现的过程中,如果需要修改需求,我们就会使用 Figma 对界面进行了微调,辅助我们进行需求的确认。
1.4 安装
虽然安装不是重点,但是我想有必要补充一下我的安装过程,以免未来遗忘。
(0) 在不安装 Vue3 的脚手架的情况下创建 Vue 应用(Vite 安装)
2022-11-17 更新:Vue3 官网 Vite 安装方式。
在安装好 npm 后,运行 npm init vue@latest
命令即可。
1 | npm init vue@latest |
(1) 准备(脚手架安装)
以 Linux 版本为例。
1 | 已经有 node。没有 Node.js 则需要先装 Node.js |
由于原系统环境中安装了 Vue2 的脚手架,所以需要进行下述命令来重新安装 Vue3:
1 | sudo npm cache clean -f |
对于上面的命令,有必要解释部分词汇。
首先,按照 Node.js 官网 的定义“Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine. ” 用我师兄的话来说,Node.js 相当于为 JavaScript 提供了运行环境,类似于 Java 的 JVM。如果没有 Node.js,JavaScript 的运行必须依赖以 Chrome 内核为典型代表的浏览器引擎;有了 Node.js,开发人员不仅可以使用 JavaScript 来撰写前端,也可以使用 JavaScript 来撰写后端等,从而进行全栈开发。
其次,npm 是一个包管理工具,类似 Python 的 pip。
我的版本情况如下所示:
(2) 创建项目(脚手架安装)
1 | vue create tool # 创建名为 tool 的 Vue3 项目 |
(3) 运行项目
我们运行 Vue 项目需要熟知如下三个命令:
1 | npm install # 安装 package.json 中罗列的包,文件夹下出现一个名为 node_moudule 的包,打开里面可以看到许多 JavaScript 和 TypeScript 代码 |
(4) Windows 版本(脚手架安装)
1 | # 已经有 node。没有 Node.js 则需要先装 Node.js |
(5) 其它
- 警告(Windows):
npm WARN config global --global, --local are deprecated. Use --location=global instead.
解决方法:使用管理员身份运行 PowerShell,运行 npm-windows-upgrade
。
查看 Vue 的版本:
npm list vue
npm 太慢
解决方法:使用淘宝镜像。
npm install -g cnpm --registry=https://registry.npmmirror.com
运行完上述命令后,即可使用 cnpm
替代 npm
。
2. 必要的基础语言技能
前文已经述及,由于太久没有写过 HTML 等语言,我现在的相关技能已经退化至基本没有了,所以我进行必要的基础语言技能复建。
2.1 JavaScript
在 Vue3 中,JavaScript 代码被包裹在标签 <script>
中。
(1) 重要数据结构的基本方法
1. Array
1 | // 1. 初始化方法 |
2. Dictionary
1 | // 1. 初始化方法 |
3. Set
1 | // 1. 初始化方法 |
4. Map
1 | // 暂时没有使用过,不做评价 |
(2) 代码调试小技巧
当有不确定的代码时,可以先在浏览器的控制台直接输入代码,查看其效果。这样比较方便调试。
(3) JavaScript 动态生成 CSS
以一段项目中的代码为例:
1 | addCSS(className, colorValue) { |
使用 document.getElementsByTagName('head')
获取页面中的 head
元素,然后在其后添加包含 CSS 代码的子节点。
2.2 CSS
在 Vue3 中,CSS 代码被包裹在标签 <style>
中。
使用选择器获取页面元素。
选择器
- 元素选择器根据元素名称来选择 HTML 元素。
p
- id 选择器使用 HTML 元素的 id 属性来选择特定元素。
#id
- 类选择器选择有特定 class 属性的 HTML 元素。
.classname
- 通用选择器()选择页面上的所有的 HTML 元素。``
- 分组选择器选取所有具有相同样式定义的 HTML 元素。
p, h1, h2
上述选择器是基础用法,我们可以使用逻辑组合伪类。比如元素的最后一个节点:p:last-child
。类似的用法可以在用到的时候进行查询。
2.3 HTML
在 Vue3 中,HTML 代码被包裹在标签 <template>
中。
3. 常见问题及解决方式
3.1 不同组件传值
(1) 子组件向父组件传值: emit
App.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<template>
<h1>{{ title }}</h1>
<Child @childVariableName="parentMethod($event)" />
</template>
<script>
import Child from "./components/Child"
export default{
name:'App',
components: {
Child,
},
data()
{
return{
title:'Old Title'
}
},
methods:{
parentMethod(title)
{
this.title = title;
},
}
</script>
<style>
</style>
Child.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<template lang="html">
<button type="button" @click='childMethod'> Update me </button>
</template>
<script>
export default {
name:'Child',
methods:{
childMethod()
{
this.$emit('childVariableName', 'New Title')
}
}
}
</script>
<style scoped>
</style>
(2) 子组件向父组件传递多个值
将 App.vue
中的 <Child @childVariableName="parentMethod($event)" />
改为 <Child @childVariableName="parentMethod" />
,将 Child.vue
中的 this.$emit('childVariableName', 'New Title')
改为 this.$emit('changeTitle', data1, data2, ...)
(3) 父组件向子组件传值: Props
Parent.vue
1 | <template> |
Child.vue
1 | <template lang="html"> |
如果所传的值是个变量,需要在变量前加冒号 :
Parent.vue
1 | <template> |
Child.vue
1 | <template lang="html"> |
通过 props 从父节点传递到子节点的数据值是不可更改的,因此如果想要对该数值进行修改等操作,需要通过重新定义一个新的变量来复制该数据,进而对新变量进行操作。
Child.vue
1 | <template lang="html"> |
(4) 父子组件之间值的动态变化
当子组件构建完毕后,父组件传递的值发生了变化,此时子组件是不会发生变化的。为了能让子组件相应父组件的变化,我们必须借助生命周期函数 watch
来监视该变量的变化。
Parent.vue
1 | <template> |
Child.vue
1 | <template v-if='showValue'> |
(5) 非父子节点传值
我的做法是在两个组件的共同父组件中进行数值的转发。这样做的原因是这两个节点属于兄弟节点,它们的关系比较密切。实际上还有其他的官方发布的非父子组件间的传值方案。
目前还没有尝试过。
3.2 钩子函数
关于 computed、methods、watch,mounted
区别见此处链接
- computed是在HTML DOM加载后马上执行的,如赋值;
- methods则必须要有一定的触发条件才能执行,如点击事件;
- watch呢?它用于观察Vue实例上的数据变动。对应一个对象,键是观察表达式,值是对应回调。值也可以是方法名,或者是对象,包含选项。所以他们的执行顺序为:默认加载的时候先computed再watch,不执行methods;等触发某一事件后,则是:先methods再watch。
- mounted 是生命周期
- created和mounted区别?
watch 同时监听多个值
首先使用 computed 定义一个复合对象吧,然后再对该对象进行 watch。
1 | export default { |
3.3 ElementPlus 组件的属性、方法、事件、插槽及样式修改
这一部分可以重点关注官方文档。由于我在此次项目中重点使用了 Vue3 的树,所以我以对 Vue3 的树进行样式修改为例。
(1) 属性
属性是指在 element 组件的基础上,在其元素上添加给定的属性,以提高其灵活性。
Tree 组件的属性节选如下:
在构建树的时候,我们可以直接将常量或变量复制给特定的属性。
在下面的代码中,我给 Tree 组件传进去了包括 data
、empty-text
、show-checkbox
等值。
1 | <template> |
(2) 方法
Tree 组件的方法节选如下:
在使用 Tree 组件的时候,我们需要先获取 Tree 组件,在下面的代码里,我通过 ref 属性给 Tree 组件添加了一个名字,在 methods
中添加了一行代码 let retNodes = this.$refs['treename'].getCheckedNodes()
以获取当前选中的节点数组。之所以可以调用 getCheckedNodes() 方法是因为在文档中清晰地告知了可以使用该方法。但是我一开始没有看明白文档中方法的使用方式,所以在查找资料上花费了很多时间。
1 | <template> |
(3) 事件
Tree 组件的事情节选如下:
回调参数的意思是,如果我们调用事件,那我们就可以获得 Tree 组件包装的函数的返回值。以 check-change 函数为例,我们自定义一个函数 handleCheckChange,当复选框被点击的时候,handleCheckChange 函数就会被执行。
1 | <template> |
(4) 插槽
ElementPlus 的插槽。仍旧以 Tree 组件为例,我想要修改树上每个节点的内容,那我就可以通过插槽对其样式进行修改。下面我决定将节点上的字变为红色。当然,我们也可以在 slot 中添加图标或任何其他想要的内容。
1 | <el-tree |
v-slot
就是我们放进去的插槽。其实,v-slot
是 Vue2 的写法,Vue3 的新写法是 <template #default="scope">
。
(5) CSS 修改
对于给定的组件,我们经常需要对其进行修改。因为官方的组件虽然做了很多基础的工作,但也给了很多限制。对 CSS 的样式进行修改这一部分内容我们需要知晓如下两种情况。
1. CSS 添加 class
以 Tree 组件为例,我在 props 里为其添加了 class。
在 class 中,如果有 no-check-node
,节点就不会显示复选框。
1 | <template> |
除了借助已有的 class 外,我们也可以自己新建 class,添加至 HTML 元素上,然后编写 CSS 代码对元素的表现形式进行控制。
2. less 和 sass
在查找 Vue3 和 ElementPlus 的资料时,搜索引擎给了我许多 Vue2 和 ElementUI 的资料,有一部分不可以使用在新版本上,但是还有一部分是可以类推到新版本上。其中,许多样式的修改使用到了 less
。使用 less
之前需要先下载 less-loader
。
1 | npm install --save-dev less-loader less |
在开发完成后,我们需要将 less 代码转换为 CSS。
首先sass和less都是css的预编译处理语言,他们引入了mixins,参数,嵌套规则,运算,颜色,名字空间,作用域,JavaScript赋值等 加快了css开发效率,当然这两者都可以配合gulp和grunt等前端构建工具使用
sass和less主要区别:在于实现方式 less是基于JavaScript的在客户端处理 所以安装的时候用npm,sass是基于ruby所以在服务器处理。
很多开发者不会选择LESS因为JavaScript引擎需要额外的时间来处理代码然后输出修改过的CSS到浏览器。关于这个有很多种方式,我选择的是只在开发环节使用LESS。一旦我完成了开发,我就复制然后粘贴LESS输出的到一个压缩器,然后到一个单独的CSS文件来替代LESS文件。另一个选择是使用LESS.app来编译和压缩你的LESS文件。两个选择都将最小化你的样式输出,从而避免由于用户的浏览器不支持JavaScript而可能引起的任何问题。尽管这不大可能,但终归是有可能的。
摘自 LESS与SASS的区别
3.4 工具
前端展示的代码高亮工具
选择了 Prism.js
。详细解释见如下两个链接:Prism.js 官网链接、Prism.js 简单使用文档
1 | todo: 如何下载 |
1 |
|
3.5 报错与特定功能实现
(1) Vue3 文件导入 JavaScript 文件的值
1 | import { importedVariable } from 'data' |
千万不可以少两个花括号 import variable from 'data'
,不然无法识别。
上面的代码生效的前提是,只有在 data.js
中有默认导出的 export default
语法时才会生效。也就是说,data.js
中有如下代码:
1 | let importedVariable = 'importedVariable' |
(2) export default
和 export
的区别
作用
export 和 export default 实现的功能相同,即:可用于导出(暴露)常量、函数、文件、模块等,以便其他文件调用。
区别
1、export 导出多个对象,export default 只能导出一个对象
2、export 导出对象需要用 { },export default 不需要 { },如:
export { A,B,C };
export default A;
3、在其他文件引用 export default 导出的对象时不一定使用导出时的名字。因为这种方式实际上是将该导出对象设置为默认导出对象,如:
假设文件 A、B 在同级目录,实现文件 B 引入文件 A 的导出对象 deObject:
文件 A:export default deObject
文件 B:import deObject from ‘./A’
或者:
import newDeObject from ‘./A’
(3) Vue3 无法正常显示图标 el-icon
我首先通过 npm 全局导入 element-icon(icon 导入方式),运行命令 npm install @element-plus/icons-vue
,图标不显示。
随后我尝试将 icon 组件导入需要使用该 icon 的文件,图标仍然不显示。
最后我将图标的 svg 复制下来,最终才正常显示 el-icon。
在 icon 的代码复制界面 选择“Copy svg content”,即可复制该代码的 svg 值,随后我们将其复制在我们需要的 HTML 代码中。
(4) Vue3 不显示 element-tree
原因一:
在 <style>
下使用了 methods 中的方法,导致找不到方法,所以 el-tree 无法显示。
原因二:传进去的 data 不是 list
报错: Uncaught (in promise) TypeError: children.indexOf is not a function
。
解决方法:在传入的 data 中添加一个 []
(5) Vue3 文件中定义了两个同名全局变量
报错:error Duplicated key
,详见解释。
解决方法:将两个同名变量修改为不同名称。
(6) 设置全部节点默认选中
实际上仅需设置选中根节点。
1 | :default-checked-keys='[rootId]' |
在 Tree 组件中添加属性 default-checked-keys
,rootId
是一个变量,表示根节点。
(7) 控制链接的大小和颜色
1 | a{ |
(8) 在 Tree 组件上添加虚线
安装网友写的插件 element-tree-line
。
1 | <template> |
上述代码效果图如下:
(9) 元素和页面一样高
使用 height='100vh'
。