前端开发环境配置及Vue开发样例

  1. 1. 编辑器及基本开发环境
    1. 1.1 VSCode编辑器
      1. 1.1.1 简介及下载
      2. 1.1.2 扩展插件
      3. 1.1.3 喜好设置
      4. 1.1.4 常见问题
    2. 1.2 Node.js环境
      1. 1.2.1 安装Node.js
      2. 1.2.2 npm换源
      3. 1.2.3 npm常见问题
      4. 1.2.4 npm安装yarn并换源
  2. 2. 前端项目的运行与打包部署
    1. 2.1 Vue项目的运行及打包部署
      1. 2.1.1 Vue项目的运行
      2. 2.1.2 Vue项目修改启动端口号
      3. 2.1.3 Vue项目的打包配置
      4. 2.1.4 打包Vue项目并部署到服务器
    2. 2.2 React项目的运行及打包部署
      1. 2.2.1 React项目的运行
      2. 2.2.2 打包React项目并部署到服务器
    3. 2.3 Angular项目的运行及打包部署
      1. 2.3.1 Angular项目的运行
      2. 2.3.2 打包Angular项目并部署到服务器
    4. 2.4 将前端项目打包成客户端
    5. 2.5 项目依赖问题的解决方案
  3. 3. 前端的一些开源脚手架
    1. 3.1 vue-element-admin
    2. 3.2 vue-admin-beautiful
    3. 3.3 ant-design-vue-pro
  4. 4. 前端的一些开源组件库
    1. 4.1 Element UI组件
    2. 4.2 Echarts可视化图表
  5. 5. 前端开发基础
    1. 5.1 Html标记语言
    2. 5.2 Css层叠样式表
    3. 5.3 JavaScript脚本语言
  6. 6. 前端的一些JS公共方法
    1. 6.1 精确的计算加减乘除
    2. 6.2 表单输入值校验
    3. 6.3 获取当前时间及当天的起始时间
    4. 6.4 获取近x日的日期
    5. 6.5 过滤符合条件的JSON数组
    6. 6.6 查找数组最大值并向上取整
  7. 7. Vue开发的常见问题
    1. 7.1 Vue生命周期
    2. 7.2 Vue父子组件互相调用
      1. 7.2.1 父组件获取子组件的数据和方法
      2. 7.1.2 子组件获取父组件的数据和方法
    3. 7.3 点击父组件重新加载子组件
    4. 7.4 Echarts组件多次调用出现id重复问题
    5. 7.5 VueX状态管理
      1. 7.5.1 解决VueX页面刷新导致数据丢失问题
      2. 7.5.2 一个简单的VueX使用示例
    6. 7.6 Element table的tooltip设置宽度不生效问题
    7. 7.7 MD5消息摘要算法
  8. 8. 使用Vue实现的一些前端效果
    1. 8.1 动态粒子特效背景
    2. 8.2 实时显示当前时间每秒更新
    3. 8.3 基于Element区间范围组件
    4. 8.4 基于Echarts引入中国地图
    5. 8.5 Echarts柱状折线混合图例
    6. 8.6 Vue解析md文件并渲染样式
    7. 8.7 基于Element引入一键置顶按钮
  9. 9. 参考资料

1. 编辑器及基本开发环境

1.1 VSCode编辑器

1.1.1 简介及下载

VS Code 是一款由微软开发且跨平台的免费源代码编辑器。该软件支持语法高亮、代码自动补全、代码重构、查看定义功能,并且内置了命令行工具和Git版本控制系统。安装几个扩展插件后,就非常适合作为前端的开发工具了。

官网下载:https://code.visualstudio.com/

VSCode界面

1.1.2 扩展插件

VS Code支持安装扩展以增强功能(设置——扩展——搜索安装扩展),常用的有以下几个:

  • EditorConfig for VS Code:此插件使用.editorconfig文件中的设置覆盖用户/工作区设置。
  • ESLint:查找并修复 JavaScript 代码中的问题。
  • Vetur:VS Code 的 Vue 工具。
  • Prettier - Code formatter:VS Code的格式化代码工具。
  • stylelint:一个检验CSS/SASS/LESS代码规范的插件。
  • Tabnine:人工智能的代码提示和补全的插件。
  • GitHub Copilot:人工智能的代码提示和补全的插件。

1.1.3 喜好设置

主题选择:Monokai Dimmed 键映射:Eclipse Keymap

自动同步:通过Github账号 自动保存:onFocusChange

1.1.4 常见问题

[1] 打开终端和控制台

  • 快捷键:Ctrl + `(键盘左上方英文状态的点)

[2] VS Code设置不自动关闭文件

  • 打开VS Code设置,Tab选择用户,在搜索框输入:workbench.editor.enablePreview,对应的设置项取消勾选即可。

[3] 文件标签栏多行显示

  • 打开VS Code设置,Tab选择工作区,在搜索框输入:workbench.editor.wrapTabs,勾选该设置项即可。

[4] 在VS Code里预览svg

  • 安装SVG Gallery扩展,然后打开svg,右键选择Open in SVG Gallery

  • 另注:svg矢量图标资源库——iconfont

1.2 Node.js环境

1.2.1 安装Node.js

方式一:用nvm安装多个版本的Node.js(建议采用此方式,因为有些前端依赖需要的Node.js不兼容)

安装:nvm官网(win端下载zip即可,安装过程会自动配置环境变量,之后打开管理员cmd输入nvm显示版本号即安装成功)

使用:使用nvm安装并管理多版本的node.js

[1] 安装多版本的node.js

1
2
3
$ nvm install v10.16.2 
$ nvm install v16.13.0
$ nvm list // 显示所有已安装的node.js

[2] 切换使用某版本的node.js

1
$ nvm use v16.13.0

注意事项:

1)安装nvm之前,如果你已经安装了Node.js,建议先把它卸载掉(控制面板处卸载即可),以免当前环境产生干扰。

2)nvm use 报错exit status 145问题:nvm安装的时候有两个安装目录,一个是nvm安装目录,一个是nodejs安装目录,这两个安装目录名不能出现空格或中文,但是nodejs默认安装目录是 C:\Program Files\nodejs,这个目录中间有空格,需要我们自定义一个安装目录,即可解决这个问题。

3)nvm use 报错exit status 1问题:这里需要用管理员身份打开cmd命令行工具,再执行nvm use即可。

方式二:直接安装某版本的Node.js

安装:Node.js官网(下载对应平台的.msi版本即可)

测试:打开cmd,输入node -vnpm -v,若显示node和npm的版本号即安装成功。

1.2.2 npm换源

由于npm 的源在国外,所以国内用户使用起来可能下载速度很慢,可换源解决此问题。

1
2
3
4
5
6
$ npm config set registry https://registry.npm.taobao.org  //配置淘宝镜像
$ npm config get registry //验证配置是否成功

// 清除设置的淘宝镜像
$ npm config delete registry
$ npm config delete disturl

注:其实我更推荐使用科学上网代理来解决,就不用配这些乱七八糟的镜像了。

1.2.3 npm常见问题

[1] npm install 安装出错问题

  • Step1:使用npm cache clean --force清除缓存。

  • Step2:打开C:\Users\xxx目录,删除node_modules文件夹中的对应包,package-lock.json文件。

    注:package-lock.json是在npm install安装时生成的一份文件,用以记录当前状态下实际安装的各个npm package的具体来源和版本号,如果没有这个文件的话,那么npm install将下载大版本下的最新的包。

  • Step3:重新执行npm install命令。

[2] npm install模块时报错not such file or directory,open ... package.json

是因为缺少 package.json 这个文件,初始化并重新安装依赖即可。

1
2
$ npm init -f
$ npm install formidable --save

[3] npm install 报错 gyp info it worked if it ends with ok npm ERR! gyp verb cli

先切换低版本node.js,亲测v10.16.2 可以,而v16.13.0不行,然后执行如下命令安装:

1
2
3
$ npm install -g mirror-config-china --registry=http://registry.npm.taobao.org
$ npm install node-sass
$ npm install

1.2.4 npm安装yarn并换源

1
2
3
$ npm install -g yarn --registry=https://registry.npm.taobao.org
$ yarn config set registry https://registry.npm.taobao.org -g
$ yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g

2. 前端项目的运行与打包部署

2.1 Vue项目的运行及打包部署

Vue2.x官方文档:https://cn.vuejs.org/v2/guide/index.html

Vue3.x官方文档:https://v3.cn.vuejs.org/guide/introduction.html

2.1.1 Vue项目的运行

方法一:先执行npm install安装依赖,再执行npm run devnpm run serve运行Vue项目。

方法二:先执行yarn install安装依赖,再执行yarn run devyarn run serve运行Vue项目。

注:npm run servenpm run dev的区别就在于vue-cli脚手架的版本,yarn同理。

2.1.2 Vue项目修改启动端口号

[1] Vue 2.x项目修改启动端口号

config文件夹中有一个index.js其中部分内容如下,port即为端口号,在这里更改即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
dev: {
env: require('./dev.env'),
port: 8080, // 端口号
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false,
}
};

[2] Vue 3.x项目修改启动端口号

Vue 3.x中修改端口号则需要在项目根目录下创建一个vue.config.js,内容如下。

1
2
3
4
5
module.exports = {
devServer: {
port: 8080, // 端口号
}
};

2.1.3 Vue项目的打包配置

[1] Vue 2.x项目的打包配置

Step1:将config/index.js中build处的assetsPublicPath由/改为./,代码如下:

1
2
3
4
5
6
7
8
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),

// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './',

注:如果未修改则生成的dist无法解析资源,无法使用

Step2:将build/utils.js中ExtractTextPlugin处添加publicPath:'../../',代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
  // Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
publicPath:'../../',
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}

[2] Vue 3.x项目的打包配置

在项目根目录新建一个vue.config.js文件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
publicPath: './',
outputDir: 'dist',
lintOnSave: true,
runtimeCompiler: true, //关键点在这
// 调整内部的 webpack 配置。
// 查阅 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/webpack.md
chainWebpack: () => {},
configureWebpack: () => {},
// 配置 webpack-dev-server 行为。
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0',
port: 8080,
https: false,
hotOnly: false,
// 查阅 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/cli-service.md#配置代理
proxy: null, // string | Object
before: app => {}
}
}

注:如果不配置打包后会出现空白页和路由不起作用的问题

2.1.4 打包Vue项目并部署到服务器

在Terminal处运行npm run build命令,出现如下内容则代表打包成功

注:服务器部署的话把打包生成的dist文件丢到网站根目录即可。

2.2 React项目的运行及打包部署

React官方文档:https://zh-hans.reactjs.org/docs/higher-order-components.html

2.2.1 React项目的运行

先执行yarn install安装依赖,再yarn start运行 React 项目。

2.2.2 打包React项目并部署到服务器

先执行yarn install安装依赖,再yarn build打包 React 项目。

打包完成后会生成一个build文件夹,服务器部署就把这个丢到网站根目录即可。

2.3 Angular项目的运行及打包部署

Angular官方文档:https://angular.cn/docs

2.3.1 Angular项目的运行

1
2
3
$ npm install -g @angular/cli   // 安装Angular CLI
$ npm install // 安装依赖
$ npm start // 运行项目

2.3.2 打包Angular项目并部署到服务器

1
$ npm run build

打包完成后会生成一个dist文件夹,服务器部署就把这个丢到网站根目录即可。

注意:不要使用 ng build --base-href ./ 命令进行打包,部署到服务器后会出现如下报错,导致刷新后页面空白。

1
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

Nginx示例配置:注意try_files一定要加,不然会出现子路由404的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
listen [::]:80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri.html $uri/ /index.html;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

2.4 将前端项目打包成客户端

将前端项目打包成客户端通常是使用 electron 开源库。

Github上有一个开源项目 nativefier,只需要一个命令就可以将任意网站打包成桌面客户端。

  • 优点:简单易用,只需要一个很简单的命令就可以打包成客户端,Linux、Windows、MacOS均可使用。
  • 缺点:生成体积大,原因是因为用的是electron,而electron包含了chromium 和 nodejs,所以一般都会120多MB。

前提:1)macOS 10.9+ / Windows / Linux 2)Node.js >= 12.9 和 npm>= 6.9

安装:npm install -g nativefier

使用:nativefier 'URL' -p 'windows'(具体用法详见:API文档 ,输入nativefier --help也可查看)

2.5 项目依赖问题的解决方案

[1] 解决 Error: error:0308010C:digital envelope routines::unsupported 报错

1
$ export NODE_OPTIONS=--openssl-legacy-provider 

[2] Node 18无法成功安装node-sass的依赖问题,更换为sass包即可

1
2
$ npm uninstall node-sass
$ npm install sass

3. 前端的一些开源脚手架

3.1 vue-element-admin

项目地址:https://github.com/PanJiaChen/vue-element-admin

官方文档:https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/

vue-element-admin

3.2 vue-admin-beautiful

项目地址:https://github.com/chuzhixin/vue-admin-beautiful-pro

vue-admin-beautiful

3.3 ant-design-vue-pro

项目地址:https://github.com/vueComponent/ant-design-vue-pro

官方文档:https://pro.antdv.com/docs/getting-started

ant-design-vue-pro

4. 前端的一些开源组件库

4.1 Element UI组件

Element UI 是一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库。

官方文档:https://element.eleme.cn/#/zh-CN/component/installation

Element-UI

另注:还有一个基于Vue3的开源组件库 Naive UI 也很不错。

4.2 Echarts可视化图表

Echarts是百度开源的一个基于 JavaScript 的开源可视化图表库,用于制作可视化图表。

官方文档:https://echarts.apache.org/examples/zh/index.html

Echarts可视化

5. 前端开发基础

HTML:HyperText Markup Language (超文本标记语言)“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。HTML不是一种编程语言,而是一种标记语言 (markup language)。

CSS:Cascading Style Sheets(层叠样式表),它是用于定义如何显示HTML 元素。CSS使得HTML写成的页面不那么单调,可以有各种颜色,大小等。

JavaScript:一种脚本语言,与Java语言没有关系,可插入HTML页面,使网页具有动态/交互性。

5.1 Html标记语言

1)添加内容

1
2
3
4
5
6
7
8
9
10
11
12
标题 <h# align="#">...</h#>
段落 <p>...</p>
空格 &nbsp;
版权符号 &copy;
注释 <!- -...- -> 另注Css内的注释是 /*...*/
换行 <br/>
水平分割线 <hr/>
居中 <center>...</center>
超链接 <a href="#" class="#">...</a> 注:target="_blank"在新窗口打开
图片 <img src="#" width="#" height="#" align="#"/>
视频 <source src="#" type='video/mp4'>
删除线 <strike>...</strike>

2)添加列表

1
2
3
有序列表<ol>+<li>
无序列表<ul>+<li>
定义列表<dl>+<dt>、<dd>

3)添加表格

1
2
3
表格 <table border="#" width="#" height="#">...</table>
行 <tr align="#" valign="top/middle/bottom">...</tr>
单元格 <td colspan/rowspan="合并列/合并行">...</td>

4)添加表单

1
2
3
4
5
6
7
1)表单 <form name="#" method="post/get" action="#">...</form>
注:name:在表单的接收页面只接收有name属性的表单元素。
action:接一个动态网页名
enctype:若表单中有文件上传,则设置该属性为multipart/form-data
2)输入控件 <input type="#" name="#" value="默认值">
注:type取值:text文本域 password 密码域 file文件域 checkbox复选框
radio单选框 button普通按钮 submit提交按钮 reset重置按钮

5)添加下拉列表/列表框

1
<select name="#" size="#">+<option value="1">  去掉size属性为列表框

6)其它

1
2
3
4
1)多行文本域 <textarea name="#" cols="#" row="#" wrap="virtual">...</textarea>
2)特殊边界 <fieldset>...</fieldset> 注:<legend>...</legend>为其定义标题
3)改进可用性 <label for="#">...</label>
注:当用户选择该标签时,浏览器自动将焦点转移到和标签相关的表单控件上。for属性应与相关元素的id属性相同

5.2 Css层叠样式表

1)样式表引入

1
2
3
4
外部样式表 <link rel="stylesheet" type="text/css" href="a1.css">
内部样式表 <style type="text/css">...</style>
内联样式表 <标记 style="...">
导入外部样式表 <style type="text/css">@import url;<style>

2)选择器

1
2
3
4
5
6
元素选择器 h1{color:red;font-size:25px;}
类选择器 .text1{color:blue;text-decoration:none;} 用class="#"调用
ID选择器 #menu{width:1280px;height:50px;} 用id="#"调用
伪类选择器 .text1:hover{color:red;text-decoration:underline;}
后代选择器 ul li{color:red;}
通配符选择器 *{margin:0px;padding:0px;}

3)内容属性

1
2
3
4
5
6
7
8
9
10
11
12
13
1)字体属性
font:font-style|font-weight|font-size|line-height|font-family
风格 粗细 字号 行高 字体
2)文本属性
文本修饰:text-decoration:none(无)|underline(下划线)|line-throungh(删除线)
文本对齐:text-align:left|center|right
首行缩进:text-indent:2em
3)列表属性
列表标记类型: list-style-type 图像符号: list-style-image:url
注:属性值:none:无 disc:实心圆 circle:空心圆 square:实心方块 decimal:1
low-roman:i upper-roman:I lower-alpha:a upper-alpha:A
4)背景属性
背景颜色:background-color 背景图像:background-image

4)盒子属性

1
2
3
4
5
6
边框:border     边距:margin      内边距:padding
1)边框 border:border-width|border-style|color
注:一个值:四边框同值 两个值:上下(1),左右(2) 四个值:上右下左
border-style属性取值:double:双直线 ridge:3D凸线
2)边距 margin(同上) 特殊:margin:0 auto实现块级居中
3)内边距 padding(同上)

5)定位属性

1
2
3
4
5
6
1)相对定位 position:relative
设置为相对定位的元素框会偏离某个距离。元素仍然保持其未定位前的形状,它原本所占的空间仍然保留。
注:在使用相对定位时,无论是否进行移动(top、bottom、left、right),元素仍占据原来的空间。因此,移动元素会导致它覆盖其它框。
2)绝对定位 position:absolute
设置为绝对定位的元素框从文档流完全删除,并相对于其包含块定位。元素定位后生成一个块级框。
注:由于绝对定位与文档流无关,所以它们可以覆盖页面上的其它元素,可以通过设置z-index属性(属性值:数字)来控制这些框的堆放次序。

6)其它

1
2
1)浮动属性 float:left|right
2)框类型属性 display:none(隐藏)|block(块级)|inline(行内)

5.3 JavaScript脚本语言

1)脚本引入

1
2
3
4
5
6
7
8
9
10
1)位于head部分的脚本(为body区域程序代码调用事件处理函数)
<script type="text/javascript">...</script>
2)位于body部分的脚本(执行后的输出成为页面内容)
同上
3)直接位于事件处理部分的代码中
<body onload="alert('欢迎');">
4)位于网页之外单独脚本文件
<script src="text.js"></script>
5)使用javascript协议(<a>的href属性可用)
<a href="javascript:alert('欢迎');>javascript</a>

2)函数

1
2
3
funcation 函数名(参数1,参数2,...,参数n){
函数体;}
注:可以没有参数,但括号必须保留。声明参数不必明确类型

3)消息对话框

1
2
3
弹出对话框 alert("文本");
确认框 confirm("文本");
提示框 prompt("文本","默认值");

4)事件处理程序

1
2
3
4
5
6
7
1)调用
通过html标记使用: <标记 事件="事件处理程序";>
通过javascript代码使用: 对象.事件=事件处理程序;
2) 常用事件
单击事件:onclick 鼠标获得焦点:onfocus 鼠标失去焦点:onblue
表单提交事件:onsubmit 页面完成事件:onload 页面改变事件:onbeforeunload
错误提示事件:onerror 鼠标悬停事件:onmouseover 域内容改变事件:onchange

6. 前端的一些JS公共方法

6.1 精确的计算加减乘除

涉及浮点数的时候,javascript的计算结果会有误差,需要精密计算的时候,可以自定义公共方法来解决。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
 /**
* 加法函数,用来得到精确的加法结果
* 调用:add(a,b)
* 返回值:a加上b的精确结果
*/
add(a, b){
let c = 0 // a的小数部分长度
let d = 0 // b的小数部分长度
try {
c = a.toString().split('.')[1].length
} catch (f) { }
try {
d = b.toString().split('.')[1].length
} catch (f) { }
let e = 10 ** Math.max(c, d) //保证a、b为整数的最小10次幂
return (a * e + b * e) / e
},
/**
* 减法函数,用来得到精确的减法结果
* 调用:sub(a,b)
* 返回值:a减去b的精确结果
*/
sub(a, b){
let c = 0 // a的小数部分长度
let d = 0 // b的小数部分长度
try {
c = a.toString().split('.')[1].length
} catch (f) { }
try {
d = b.toString().split('.')[1].length
} catch (f) { }
let e = 10 ** Math.max(c, d) //保证a、b为整数的最小10次幂
return (a * e - b * e) / e
},
/**
* 乘法函数,用来得到精确的乘法结果
* 调用:mul(a,b)
* 返回值:a乘以b的精确结果
*/
mul(a, b){
let c = 0 // a的小数部分长度
let d = 0 // b的小数部分长度
try {
c = a.toString().split('.')[1].length
} catch (f) { }
try {
d = b.toString().split('.')[1].length
} catch (f) { }

return (Number(a.toString().replace('.', '')) * Number(b.toString().replace('.', ''))) / (10 ** (c + d))
},
/**
* 除法函数,用来得到精确的除法结果
* 调用:div(a,b)
* 返回值:a除以b的精确结果
*/
div(a, b){
let c = 0
let d = 0
try {
c = a.toString().split('.')[1].length
} catch (f) { }
try {
d = b.toString().split('.')[1].length
} catch (f) { }
const molecular = Number(a.toString().replace('.', '')) * (10 ** (c + d))
const denominator = Number(b.toString().replace('.', '')) * (10 ** (c + d))
return molecular / denominator / (10 ** (c - d))
}

6.2 表单输入值校验

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 验证正整数+正小数+0
*/
checkIsPositive(rule, value, callback){
var reg = /^\d+(?=\.{0,1}\d+$|$)/
if(reg.test(value)) {
callback()
}else{
callback(new Error('请输入大于等于0的正数'))
}
},
/**
* 验证正整数+正小数
*/
checkIsPositiveEx0(rule, value, callback){
var reg = /^(\d|[1-9]\d+)(\.\d+)?$/
if(reg.test(value)) {
if(value == '0') {
callback(new Error('请输入大于0的正数'))
} else {
callback()
}
}else{
callback(new Error('请输入大于0的正数'))
}
},
/**
* 验证正整数+0
*/
checkIsPositiveInteger(rule, value, callback){
var reg = /^(0|[1-9][0-9]*)$/
if(reg.test(value)) {
callback()
}else{
callback(new Error('请输入大于等于0的正整数'))
}
},
/**
* 验证正整数
*/
checkIsPositiveIntegerEx0(rule, value, callback){
var reg = /^([1-9][0-9]*)$/
if(reg.test(value)) {
callback()
}else{
callback(new Error('请输入大于0的正整数'))
}
}

6.3 获取当前时间及当天的起始时间

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 获取当前时间
* @returns
*/
getDayTime: function(){
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth()+1;
month=month>9?month:('0'+month);
var day=date.getDate();
day=day>9?day:('0'+day);
var hh=date.getHours();
hh=hh>9?hh:('0'+hh);
var mm=date.getMinutes();
mm=mm>9?mm:('0'+mm);
var ss=date.getSeconds();
ss=ss>9?ss:('0'+ss);
var time=year+'-'+month+'-'+day+' '+hh+':'+mm+':'+ss;
return time;
},
/**
* 获取当天的起始时间
* @returns
*/
getDayStartTime: function () {
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth()+1;
month=month>9?month:('0'+month);
var day=date.getDate();
day=day>9?day:('0'+day);
var time=year+'-'+month+'-'+day+' '+'00'+':'+'00'+':'+'00';
return time;
},
/**
* 获取当天的结束时间
* @returns
*/
getDayEndTime: function () {
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth()+1;
month=month>9?month:('0'+month);
var day=date.getDate();
day=day>9?day:('0'+day);
var time=year+'-'+month+'-'+day+' '+'23'+':'+'59'+':'+'59';
return time;
},

6.4 获取近x日的日期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 生成近x日的日期
* @param {*} day
* @returns
*/
getDay(day){
var today = new Date();
var targetday_milliseconds=today.getTime() + 1000*60*60*24*day;
today.setTime(targetday_milliseconds);
var tYear = today.getFullYear();
var tMonth = today.getMonth();
var tDate = today.getDate();
tMonth = this.doHandleMonth(tMonth + 1);
tDate = this.doHandleMonth(tDate);
return tYear+"-"+tMonth+"-"+tDate;
},
doHandleMonth(month){
var m = month;
if(month.toString().length == 1){
m = "0" + month;
}
return m;
}

6.5 过滤符合条件的JSON数组

1
2
3
4
5
6
getFilterData(data,code){
var dataFilter = data.filter((r) => {
return r.code == code;
});
return dataFilter;
},

注:data是待过滤的JSON数组,code是JSON数组里用于过滤的项。

6.6 查找数组最大值并向上取整

需求情景:在绘制Echarts柱状图和折线图的时候,有时数据上限不能确定,这个方法可以根据返回数据的最大值动态获取上限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 /**
* 查找数字字符串数组中的最大值,并以千为单位向上取整
* @param {*} arrs
* @returns
*/
findArrayMaxCeil(arrs){
var max = parseFloat(arrs[0]);
for(var i = 1, ilen = arrs.length; i < ilen; i+=1) {
if(parseFloat(arrs[i]) > max) {
max = parseFloat(arrs[i]);
}
}
max = (Math.ceil(max/1000)*1000).toString();
return max;
},

// 具体调用处
min: 0,
max: this.findArrayMaxCeil(this.data),
interval: this.findArrayMaxCeil(this.data)/10,

7. Vue开发的常见问题

7.1 Vue生命周期

下图展示了Vue的生命周期,摘自Vue2.x官网。虽不需要立马弄明白所有东西,不过随着不断学习和使用,它的参考价值会越来越高。

vue生命周期

注:mounted和created的区别

  • created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。

  • mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

通常created使用的次数多,而mounted通常是在一些插件的使用或者组件的使用中进行操作。比如在created中无法对Echarts进行一些初始化配置,一定要等这个html渲染完后才可以进行,那么mounted就是不二之选。

7.2 Vue父子组件互相调用

7.2.1 父组件获取子组件的数据和方法

Step1:调用子组件的时候,定义一个ref

1
<headerchild ref="headerChild"></headerchild>

Step2:在父组件里面通过如下形式进行调用

1
2
this.$refs.headerChild.属性
this.$refs.headerChild.方法

7.1.2 子组件获取父组件的数据和方法

在子组件里面通过如下形式进行调用

1
2
this.$parent.属性
this.$parent.方法

注:使用this.$parent.属性有时会出现调不到父组件属性的情况,此时建议使用props将父组件属性传递给子组件,下面是一个示例。

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
父组件:
<input type="text" v-model="name">
<!-- 引入子组件 -->
<child :inputName="name"></child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
},
data () {
return {
name: ''
}
}
}
</script>

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
子组件:
<span>{{inputName}}</span>
</div>
</template>
<script>
export default {
// 接受父组件的值
props: ['inputName']
}
</script>

7.3 点击父组件重新加载子组件

我们经常会遇到通过给在父组件中引用的子组件标签上添加属性,来渲染可以拥有不同数据的子组件的需求。由于子组件的 created() 生命周期函数只执行一次,因此可能会出现数据没有更新的情况。

这时候就用到了 Vue 中的 key 属性,它是用来给 Vue 元素渲染的时候用的,每次渲染的时候会去拿这个 key 值做对比,如果这一次的key 值和上一次的 key 值是不一样的才会重新渲染dom 元素,否则保持上一次的元素状态。

根据这个原理我们可以给 key 直接绑定一个 时间戳,点击父组件的时候改变这个时间戳即可实现子组件的重新加载。

父组件:

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
<template>
<div>
<div>
<h1>父级</h1>
<button @click="handleLoad">点击重新加载子级</button>
</div>
<children :key="timer"></children>
</div>
</template>
<script>
import children from '@/components/parent/children'
export default {
name: 'parent',
components: { children },
data () {
return {
timer: ''
}
},
methods: {
handleLoad () {
this.timer = new Date().getTime()
}
}
}
</script>

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
子级
</div>
</template>
<script>
export default {
name: 'children',
data () {
return {}
},
created () {
console.log('重新加载啦')
}
}
</script>

7.4 Echarts组件多次调用出现id重复问题

需求情景:有时候我们会用到同一个Echarts样式,只是在不同地方灌入不同的数据,用id作为选择器的时候只会渲染一个。为了解决这个问题,我们可以将Echarts封装成组件调用,干掉id,使用ref。(注:写到一个文件里的话用ref也是不行的)

1
2
3
4
5
6
7
//修改前
<div id="chart"></div>
let myChart = this.$echarts.init(document.getElementById(chart));

//修改后
<div ref="chart"></div>
let myChart = this.$echarts.init(this.$refs.chart);

7.5 VueX状态管理

VueX 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

官方文档:https://vuex.vuejs.org/zh/ (有关VueX的调试建议使用官方的 Vue.js devtools 扩展,里面有个专门的VueX模块)

VueX有State、Getters、Mutations、Actions、Modules这几个核心概念,建议先把它看明白再来用,具体见官方文档。

7.5.1 解决VueX页面刷新导致数据丢失问题

VueX的数据是存在内存当中的,当页面刷新之后,VueX的数据自然会丢失。我们可以使用localStorage或者sessionStroage来解决,在页面刷新时把VueX的值存起来,再在页面加载时将其取出替换,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
created() {
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem("store")) {
this.$store.replaceState(
Object.assign(
{},
this.$store.state,
JSON.parse(sessionStorage.getItem("store"))
)
);
}
//在页面刷新时将VueX里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
sessionStorage.setItem("store", JSON.stringify(this.$store.state));
});
},

注:可以使用sessionStorage.removeItem("store")来清除缓存数据。

7.5.2 一个简单的VueX使用示例

系统字典一般都是动态的,后端专门提供一个查询系统字典的接口。然后前端在请求接口、渲染页面的时候,通过系统字典把抽象的数据转换成展示字段。但是这个过程我们不可能让它每次转换都要请求一次字典接口,因此我们可以在登录的时候把它存入到VueX里缓存起来,每次转换的时候请求这个即可。下面是一个简单的示例:

[1] 接口请求及公共函数

/api/code/index.js

1
2
3
4
5
6
7
8
9
import axios from '@/api'

export const getCodeData = (data) => {
return axios.request({
url:'/code',
method:'post',
data:data
});
};

common/common.js

1
2
3
4
5
6
7
8
9
import { getCodeData } from '@/api/code'

setCodeList(){
this.request(getCodeData,'',this,data => {
this.$store.commit("code/setCodeList", {
codeList: data
});
})
},

[2] VueX相关配置

/store/modules/code.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const state = {
codeList: []
}
const getters = {
codeList:state => state.codeList,
}
const actions = {}
const mutations = {
setCodeList(state, codeList) {
state.codeList = codeList;
}
}

export default {
namespaced: true,
state,
getters,
actions,
mutations
}

/store/modules/index.js

1
2
3
4
5
import code from './code.js' 

export default {
code
}

/store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state.js'
import mutations from './mutations.js'
import actions from './actions.js'
import getters from './getters.js'
import modules from './module/index.js'

Vue.use(Vuex);

export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules
});

[3] VueX的调用

登录逻辑里的相关部分

1
2
3
4
5
sessionStorage.removeItem("codeList") // 清除sessionStorage里缓存的codeList
this.setCodeList(); // 请求接口,将系统字典存入VueX
setTimeout(() =>{
this.$router.push('/'); // 设置延时是为了解决登录时VueX还没请求完就加载页面的问题。
},1000);

在首页里加上上述“解决VueX页面刷新导致数据丢失问题”的代码,此处不再赘述。

筛选出指定类型的系统字典可以在公共方法里写一个过滤器来实现,比如:

1
2
3
4
5
6
getFilterCodeData: function (res, code, value) {
var codeFilter = res.filter((r) => {
return r.code == code;
});
return codeFilter;
}

具体页面的调用转换

1
2
3
4
5
6
7
computed:{
codeList(){
return this.$store.state.code.codeList.codeList;
}
},

// 在具体方法里用this.codeList获取字典,再调用过滤器筛选,再将接口返回值通过字典转换成展示值即可

7.6 Element table的tooltip设置宽度不生效问题

1
2
3
4
5
6
<style lang="css">
.el-tooltip__popper {
max-width: 400px;
line-height: 180%;
}
</style>

注意:修改elementui自带样式的话,不能在<style scoped></style>中修改,因为不会生效。

7.7 MD5消息摘要算法

MD5算法是典型的消息摘要算法,可采用MD5算法校验文件完整性,计算目标文件的数字指纹,前端的用法如下:

Step1:先下载md5的包

1
$ npm install js-md5 --save-dev

Step2:按需引入并使用

1
2
import md5 from "js-md5"; // 引用
md5(this.encryption) // 使用

注意:不要拿MD5算法当加密算法用,它可以被完全破解,不要用它来加密涉及用户密码这种敏感的信息,加密这种信息建议使用AES、RSA等非对称加密算法。

8. 使用Vue实现的一些前端效果

8.1 动态粒子特效背景

下图那些类似于星座图的点和线,是由vue-particles生成的,不仅自己动,而且能与用户鼠标事件产生互动,是非常炫的一种动态特效,可以在Vue项目中使用,需要安装第三方依赖。

Vue动态粒子特效

Step1:安装vue-particles

1
$ npm install --save vue-particles

Step2:引入 main.js 文件

1
2
3
import Vue from 'vue'
import VueParticles from 'vue-particles'
Vue.use(VueParticles)

Step3:具体使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div id="app">
<vue-particles
class="login-background"
color="#97D0F2"
:particleOpacity="0.7"
:particlesNumber="50"
shapeType="circle"
:particleSize="4"
linesColor="#97D0F2"
:linesWidth="1"
:lineLinked="true"
:lineOpacity="0.4"
:linesDistance="150"
:moveSpeed="3"
:hoverEffect="true"
hoverMode="grab"
:clickEffect="true"
clickMode="push">
</vue-particles>
</div>
</template>

解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
color: String类型。默认’#dedede’。粒子颜色。
particleOpacity: Number类型。默认0.7。粒子透明度。
particlesNumber: Number类型。默认80。粒子数量。
shapeType: String类型。默认’circle’。可用的粒子外观类型有:“circle”,“edge”,“triangle”,“polygon”,“star”。
particleSize: Number类型。默认80。单个粒子大小。
linesColor: String类型。默认’#dedede’。线条颜色。
linesWidth: Number类型。默认1。线条宽度。
lineLinked: 布尔类型。默认true。连接线是否可用。
lineOpacity: Number类型。默认0.4。线条透明度。
linesDistance: Number类型。默认150。线条距离。
moveSpeed: Number类型。默认3。粒子运动速度。
hoverEffect: 布尔类型。默认true。是否有hover特效。
hoverMode: String类型。默认true。可用的hover模式有: “grab”, “repulse”, “bubble”。
clickEffect: 布尔类型。默认true。是否有click特效。
clickMode: String类型。默认true。可用的click模式有: “push”, “remove”, “repulse”, “bubble”。

说明:通常使用我们都是直接引入这个标签,然后在这个标签后面放上自己的内容,如果要当作背景的话,设置定位position:absolute或者position:fixed

8.2 实时显示当前时间每秒更新

可视化大屏一般都是全屏展示的,所以项目可能会在左上角或者右上角实时显示当前时间。以下代码可以实现yyyy-MM-dd hh:mm:ss格式当前时间每秒更新的效果。

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
29
30
31
32
33
34
35
36
37
38
<div id="app">
<b>{{dateFormat(date)}}</b>
</div>

<script>
export default {
data() {
return {
date: new Date()
};
},
mounted() {
let _this = this; // 声明一个变量指向Vue实例this,保证作用域一致
this.timer = setInterval(() => {
_this.date = new Date(); // 修改数据date
}, 1000)
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer); // 在Vue实例销毁前,清除我们的定时器
}
},
methods:{
dateFormat(time) {
var date=new Date(time);
var year=date.getFullYear();
// 在日期格式中,月份是从0开始的,因此要加1。使用三元表达式在小于10的前面加0,以达到格式统一。
var month= date.getMonth()+1<10 ? "0"+(date.getMonth()+1) : date.getMonth()+1;
var day=date.getDate()<10 ? "0"+date.getDate() : date.getDate();
var hours=date.getHours()<10 ? "0"+date.getHours() : date.getHours();
var minutes=date.getMinutes()<10 ? "0"+date.getMinutes() : date.getMinutes();
var seconds=date.getSeconds()<10 ? "0"+date.getSeconds() : date.getSeconds();
// 拼接
return year+"-"+month+"-"+day+" "+hours+":"+minutes+":"+seconds;
}
}
};
</script>

8.3 基于Element区间范围组件

管理系统中经常会有要求对某个字段进行区间阈值设置或者作为筛选条件的需求,而Element中除了日期区间选择之外并没有特别契合的组件,可以自己手动写一个。

主要思路:[1] 单个表单校验:必填项校验、正整数校验、区间校验 [2] 关联校验:右侧阈值不得小于左侧阈值

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<template>
<el-form ref="form" :model="form" :rules="rules">
<el-form-item prop="min">
<el-input v-model="form.min" @change="handleMinChange" />
</el-form-item>
~
<el-form-item prop="max">
<el-input v-model="form.max" @change="handleMaxChange" />
</el-form-item>
</el-form>
</template>

<script>
const MIN_NUMBER = 1;
const MAX_NUMBER = 100000;

export default {
data() {
return {
form: { min: '20', max: '100000' },
rules: {
min: [
{ required: true, message: '必填项,请维护', trigger: 'blur' },
{ validator: this.validateCom, trigger: 'blur' },
{ validator: this.validateMin, trigger: 'blur' },
],
max: [
{ required: true, message: '必填项,请维护', trigger: 'blur' },
{ validator: this.validateCom, trigger: 'blur' },
{ validator: this.validateMax, trigger: 'blur' },
],
},
};
},
methods: {
getFormData() {
const ret = {};
this.$refs.form.validate((valid) => {
ret.valid = valid;
ret.form = this.form;
});
return ret;
},
resetForm() {
this.$refs.form.resetFields();
},
handleMinChange() {
this.$refs.form.validateField('max');
},
handleMaxChange() {
this.$refs.form.validateField('min');
},
validateCom(rule, value, callback) {
const one = Number(value);
if (Number.isInteger(one)) {
if (one < MIN_NUMBER) {
return callback(new Error('输入值必须大于0'));
} else if (one > MAX_NUMBER) {
return callback(new Error('输入值必须小于100000'));
}
return callback();
}
return callback(new Error('输入值必须为正整数'));
},
validateMin(rule, value, callback) {
const one = Number(value);
const max = Number(this.form.max);
if (!max || one < max) {
return callback();
}
return callback(new Error('输入值不得大于最大阈值'));
},
validateMax(rule, value, callback) {
const one = Number(value);
const min = Number(this.form.min);
if (!min || one > min) {
return callback();
}
return callback(new Error('输入值不得小于最小阈值'));
},
},
};
</script>

8.4 基于Echarts引入中国地图

Echarts中国地图

先用npm安装一下echarts依赖

1
$ npm install echarts --save

再去网上搜一个china.js文件(官方已停止下载,但很好搜,随便找个带中国地图的项目里就有),放到src/asset/js目录下。

下面给出上图实现效果的简单代码示例:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<template>
<div class="home">
<div class="chinaMap" id="chinaMap" style="width: 600px;height:600px;">
</div>
</div>
</template>

<script>

import * as echarts from 'echarts'
import '../../../../src/assets/js/china.js'

export default {
name:'china-map',
mounted() {
this.chinaMap();
},
methods: {
chinaMap(){
var data = [
{name: '深圳', value: [114.07,22.62]},
{name: '北京', value: [116.46,39.92]},
{name: '杭州', value: [120.19,29.96]},
{name: '苏州', value: [120.62,32.62]},
{name: '成都', value: [104.06,30.67]},
{name: '广州', value: [113.23,23.76]},
{name: '上海', value: [121.48,31.22]},
]
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('chinaMap'));

// 指定图表的配置项和数据
var option = {
tooltip : {
trigger: 'none',
},
geo: {
map: 'china',
aspectScale: 0.75, //长宽比
layoutCenter: ['50%', '50%'],
layoutSize: 600,
itemStyle: {
// 定义地图样式
normal: { // 普通状态下的样式
areaColor: '#cfcfcf',
borderColor: '#fff',
show: false
},
emphasis: { // 高亮状态下的样式
areaColor: '#cfcfcf',
borderColor: '#fff',
show: false
}
},
select:{
label:{
show: false
},
itemStyle:{
color: '#fff'
}
},
label:{ //不显示省份名称
normal: {
show: false
},
emphasis: {
show: false
}
},
},
series : [
{
coordinateSystem: 'geo', // series坐标系类型
type: 'scatter', //散点图
mapType: 'china',
roam: false,
data: data,
symbol:'path://M512 736.981333L775.68 896l-69.76-299.904L938.666667 394.410667l-306.816-26.325334L512 85.333333 392.149333 368.085333 85.333333 394.410667l232.746667 201.685333L248.32 896z',
symbolSize: 12,
encode: {
value: 2
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
hoverAnimation: true,
label: {
formatter: '{b}',
position: 'right',
lineHeight : 15,
show: true,
emphasis:{
textStyle:{
color: '#EC652A' //设置活动状态下字体样式,会跟随散点高亮
}
}
},
itemStyle: {
normal: { // 散点图标普通状态下的样式
color: '#333'
},
emphasis: { // 散点图标高亮状态下的样式
color:'#EC652A',
},
shadowBlur: 10,
shadowColor: '#333'
},
zlevel: 1,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
}
},
}
</script>

<style lang="css" scoped>
.chinaMap{
margin: 0 auto;
}
</style>

具体样式根据自己需求进行调整吧,如果需要可下钻的地图,请参考:https://github.com/xiaofan9/echarts-china-map 项目

8.5 Echarts柱状折线混合图例

以下是一个柱状折线混合的Echarts图例,也可以用它轻易的拆分出单独的柱状图或折线图。

Echarts柱状折线混合图例

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<template>
<div class="home">
<div class="mixChart" id="mixChart" style="width: 1500px;height:500px;">
</div>
</div>
</template>

<script>
import * as echarts from 'echarts'

export default {
name:'mixChart',
mounted() {
this.trendChart();
},
methods: {
trendChart(){
var myChart = echarts.init(document.getElementById('mixChart'));
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
}
},
legend: {
data: ['蒸发量', '降水量', '平均温度']
},
xAxis: [
{
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '水量',
min: 0,
max: 250,
interval: 50,
axisLabel: {
formatter: '{value} ml'
}
},
{
type: 'value',
name: '温度',
min: 0,
max: 25,
interval: 5,
axisLabel: {
formatter: '{value} °C'
}
}
],
series: [
{
name: '蒸发量',
type: 'bar',
data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
},
{
name: '降水量',
type: 'bar',
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
},
{
name: '平均温度',
type: 'line',
yAxisIndex: 1,
data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
}
]
};
myChart.setOption(option);
}

},
}
</script>

<style lang="css" scoped>
.mixChart{
margin: 0 auto;
}
</style>

附:Echarts图例样式调整参考

[1] ECharts中的 formatter中的a,b,c,d等参数的意义 from CSDN

[2] 关于如何设置echart图例(legend)的位置 from CSDN

[3] echarts标题(title)配置 from CSDN

8.6 Vue解析md文件并渲染样式

需求情景:比如将README说明文档展示到前端页面,可以通过Vue直接解析md文件渲染样式实现。

Step1:安装解析md文件和渲染样式的包

1
2
$ npm install markdown-loader [email protected] --save     // 解析md文件
$ npm install github-markdown-css --save // 渲染样式

注:html-loader安装0.5.5版本,用最新版的话后续会报Module build failed (from ./node_modules/**html-loader**/dist/cjs.js): TypeError: this.getOptions is not a function的错儿,无法解析。

Step2:打开webpack.config.js文件,添加如下规则:

1
2
3
4
5
6
7
8
9
10
11
12
{
test: /\.md$/,
use: [
{
loader: "html-loader"
},
{
loader: "markdown-loader",
options: {}
}
]
},

注:如果不添加规则的话后续会报You may need an appropriate loader to handle this file type.的错儿,无法解析。

Step3:在main.js中将github-markdown-css导入

1
import 'github-markdown-css';

Step4:vue解析md并渲染样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div v-html="md" class="markdown-body" ></div>
</template>

<script>
import demo from './md/README.md';
export default {
name: 'test',
data () {
return {
md: demo
};
},
methods: {}
};
</script>

8.7 基于Element引入一键置顶按钮

官方文档对于一键置顶功能的实现描述不够详细,这里结合上述Markdown页面给出一个示例:

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
29
30
31
32
33
34
35
36
37
38
<template>
<div class="wraper">
<template>
<el-backtop target=".wraper">
<div class ='up'>UP</div>
</el-backtop>
</template>
<div v-html="md" class="markdown-body"></div>
</div>
</template>

<script>
import from './md/README.md';
export default {
name:'test',
data () {
return {
md: demo
};
},
}
</script>

<style lang="css" scoped>
.wraper {
height: 100vh;
overflow-x: hidden;
}
.up{
height: 100%;
width: 100%;
background-color: #f2f5f6;
box-shadow: 0 0 6px rgba(0,0,0, .12);
text-align: center;
line-height: 40px;
color: #1989fa;
}
</style>

注:target 跟的是触发滚动的对象,如果这个页面是作为一个组件嵌入到公共页面里,那么这里的 target 要用外部的类选择器,然后底下的.wraper也要改一下名字。

9. 参考资料

[1] fantastic-admin代码规范 from Gitee

[2] vscode怎么设置打开新文件的时候不关闭没有修改过的旧文件?from segmentfault

[3] vscode 文件标签栏多行显示 from CSDN

[4] npm run serve和npm run dev的区别 from 腾讯云

[5] npm install 安装出错时尝试过的方法 from CSDN

[6] npm换源与恢复官方源 from 思考生活

[7] Vue开发环境中修改端口号 from segmentfault

[8] vue项目打包-上传-部署到linux的nginx服务器上 from CSDN

[9] vue-cli如何打包和图片上传丢失问题 from CSDN

[10] VUE项目打包(解决背景图片不显示问题) from CSDN

[11] vue3.0以上关于打包后出现空白页和路由不起作用 from CSDN

[12] nativefier使任何网页成为桌面应用程序 from Github

[13] Nginx Windows详细安装部署教程 from 博客园

[14] vue 登录页背景-粒子特效(Vue-Particles)from 掘金

[15] Vue页面上实时显示当前时间,每秒更新 from cnblogs

[16] vue实时显示当前时间且转化为“yyyy-MM-dd hh:mm:ss”格式

[17] 基于element的区间选择组件 from segmentfault

[18] ECharts实现地图散点图 from efe

[19] ECharts实现的中国地图散点图示例 from Github

[20] Echarts中国地图,支持下钻 from Github

[21] js校验大于等于0的正数和正整数 from 简书

[22] js的加减乘除 from 掘金

[23] vue 解析md文件 并渲染样式 from CSDN

[24] Module build failed (from ./node_modules/html-loader/dist/cjs.js): TypeError: this.getOptions is not a function报错 from CSDN

[25] 解决vue封装的echarts组件多次调用出现id重复问题 fromCSDN

[26] vue.js 父组件主动获取子组件的数据和方法、子组件主动获取父组件的数据和方法 from segmentfault

[27] Vue生命周期中mounted和created的区别 from CSDN

[28] vue+element-ui 回到顶部组件backTop from CSDN

[29] 将数据存入vuex中以及从vuex中取出数据 from CSDN

[30] 解决vuex页面刷新导致数据丢失问题 from segmentfault

[31] show-overflow-tooltip显示的宽度设置、.el-tooltip__popper无效问题解决 from CSDN

[32] vue项目,父组件每次点击按钮,重新加载子组件 from CSDN

[33] Vue2.0的三种常用传值方式、父传子、子传父、非父子组件传值 from CSDN

[34] JS生成一个最近一周日期的数组 from CSDN

[35] vue md5加密用法 from 掘金

[36] Angular11(Cli) 在打包 ng build 后的常见问题处理方案 from CSDN

[37] 在 Nginx 中部署 Angular 应用 - 解决路由冲突 404 问题 from CSDN

[38] windows系统下如何安装多版本node from 稀土掘金

[39] nvm安装,nvm use 一直报错exit status 1 或 exit status 145 问题 from 前端网

[40] npm install 报错 gyp info it worked if it ends with ok npm ERR! gyp verb cli from CSDN

[41] [问题]项目无法启动,error:0308010C:digital envelope routines::unsupported from Github Issues

[42] node-sass install ERROR with Node 18 version from stackoverflow