vue全家桶+Electron+Quasar框架快速构建跨平台应用
OrdinaryRoad
上海
0
6
57
0
友情提示:此篇文章大约需要阅读 57分9秒
> 原文链接:[vue全家桶+Electron+Quasar框架快速构建跨平台应用\_quasar框架build electron-CSDN博客](https://blog.csdn.net/leida_wt/article/details/113495857)
---
# vue全家桶+Electron+Quasar框架快速构建跨平台应用
最近在科研和横向中遇到不少GUI开发的需求,这些项目中,快速、低成本的构建跨平台GUI应用是重中之重,典型的解决方案有Qt和基于web的方案等。鉴于笔者的需求主要是呈现一些科研图表或视频流,并无复杂的交互逻辑,故选择基于web的方案比较合适。具体的,根据之前的使用经验,选择vue来做界面逻辑,vue的生态比较完善,有很多GUI框架可用,并选择Electron打包桌面端。
本文记录学习和使用vue全家桶+Electron+Quasar框架快速构建跨平台应用的一些心得。
## 先导知识
### JS+HTML+CSS三件套
[MDN web docs](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web) (强烈推荐)
[廖雪峰JS教程](https://www.liaoxuefeng.com/wiki/1022910821149312)
[w3school HTML教程](https://www.w3school.com.cn/html5/index.asp)
[w3school CSS教程](https://www.w3school.com.cn/css3/index.asp)
[阮一峰的网络日志](http://www.ruanyifeng.com/blog/javascript/)
### 前端构建工具
[廖雪峰Node.js教程](https://www.liaoxuefeng.com/wiki/1022910821149312/1023025235359040)
[webpack官方文档](https://www.webpackjs.com/concepts/)
### Electron
[Electron官方文档](https://www.electronjs.org/docs/tutorial/quick-start#%E5%BF%AB%E9%80%9F%E5%90%AF%E5%8A%A8%E6%8C%87%E5%8D%97)
[electron-api-demo](https://github.com/electron/electron-api-demos/releases):了解electron特性的一个良好选择。
[electron-builder打包见解](https://juejin.cn/post/6844903693683261453)
### vue.js
[vue.js官方文档](https://cn.vuejs.org/v2/guide/)
### UI组件框架
[Vuetify UI库](https://vuetifyjs.com/zh-Hans/introduction/why-vuetify/):优秀vue组件库,受vue官方推荐
[element UI库](https://element.eleme.cn/#/zh-CN) :饿了么前端团队推出的组件库
[Quasar UI库](http://www.quasarchs.com/introduction-to-quasar):十分优秀的多平台UI解决方案
本文使用Quasar框架提供UI支持。Quasar框架是近两年新发展起来的全栈UI框架,组件非常全面,强大,迭代热度很高。
### 常用js库
[axios](https://github.com/axios/axios):基于promise 的HTTP 库
ffmpeg相关:
1. [node-fluent-ffmpeg](https://github.com/fluent-ffmpeg/node-fluent-ffmpeg)
2. [ffprobe-installer](https://www.npmjs.com/package/@ffprobe-installer/ffprobe)
3. [node-ffmpeg-installer](https://github.com/kribblo/node-ffmpeg-installer)
[lowdb](https://github.com/typicode/lowdb) JSON数据库,适合用于在本地存储小数据
## 环境配置
### 基于vue-cli(废弃)
安装Node.js环境,[安装包下载](https://nodejs.org/zh-cn/download/)。
为npm包管理器更换华为源(或淘宝源),加速国内访问速度:
```
npm config set registry https://mirrors.huaweicloud.com/repository/npm/
npm config set disturl https://mirrors.huaweicloud.com/nodejs/
npm config set electron_mirror https://mirrors.huaweicloud.com/electron/
```
全局安装vue-cli工具,该工具为新建vue工程提供了极大的便利。
```
npm install -g @vue/cli
```
命令行键入“vue ui”启动vue-cli的可视化界面:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204225237758.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)使用默认配置新建工程。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204225316620.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204225327285.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)等待CLI工具完成依赖下载和资源配置,随后自动进入项目控制台:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204225459660.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)下面通过插件方式安装Quasar UI库,Quasar已经维护了对vue-cli-plugin的支持,非常方便,但官方推荐使用Quasar-cli取而代之。在plugins中搜索并安装vue-cli-plugin-quasar。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210220104922974.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
添加成功后,编译一下检查配置是否成功。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204230047378.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)若一切正常,则可看到demo界面:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210204230125803.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)用相同的方法添加electron-builder插件。
electron插件会自动配置两个新的任务选项用于编译打包:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210205000315724.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)首次执行electron:build的时候会从github下载所需的二进制依赖文件,由于众所周知的原因,下载龟速,经常失败。对此可以通过手动下载依赖文件来解决,见[这里](https://www.huaweicloud.com/articles/473ca1dca81f29abc5d721952d3096bc.html)。
所需的依赖文件可从[这里](https://repo.huaweicloud.com/electron/)和[这里](https://mirrors.huaweicloud.com/electron-builder-binaries/)快速下载(ps. 赞一下华为云提供的镜像服务)。
顺利执行打包后,可在【项目路径】/dist\_electron下找到打包好的程序。
至此,借助vue-cli工具,我们得以快速完成了程序框架的配置。
### 基于quasar-cli(推荐)
本节使用wsl2提供的ubuntu18.04为运行环境。
#### 基础环境配置
quasar框架推荐使用quasar-cli构建应用程序,quasar-cli类似vue-cli,但与quasar框架结合更紧密,省去了很多繁琐的配置。鉴于在windows上安装quasar-cli套件生成的工程的依赖文件时会通过node-gyp编译部分依赖包,存在一些兼容性问题,故笔者转而使用linux环境进行开发,通过WSL2提供ubuntu-18.04环境。参考[这里](https://docs.microsoft.com/zh-cn/windows/nodejs/setup-on-wsl2)在win10上配置WSL2和node环境。完成node环境配置后,换npm源,安装cli,建立一个demo工程:
```
npm config set registry https://registry.npm.taobao.org
npm install -g @quasar/cli
quasar create <folder_name>
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210214142904347.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)按提示完成工程配置,最后,quasar-cli会执行npm install安装依赖文件。
启动开发服务器,即可看到demo工程:
```
quasar dev
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210214143221960.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
#### electron环境配置
除了对基础的单页面应用开发的支持,quasar-cli还提供使用electron和Cordova打包PC端和移动端混合应用的能力。如若需添加electron打包功能,执行:
```
quasar mode add electron
```
添加electron打包组件,并执行quasar dev -m electron启动开发服务器。
注意,由于WSL2不包含GUI部分,故在打包electron时会遇到一些依赖问题(缺少so包),只需按照报错信息使用apt install对应的包即可。此外,针对GUI程序无法显示的问题,我们可以通过Xserver查看electron程序的GUI界面。使用自带Xserver的客户端访问WSL(如mobaxterm),将如下内容填入\~/.bashrc,使得WSL2的图形界面通过Xserver桥接:
```
export DISPLAY=$(awk '/nameserver / {print $2; exit}' /etc/resolv.conf 2>/dev/null):0
export LIBGL_ALWAYS_INDIRECT=1
```
之后再执行quasar dev -m electron便可查看electron应用。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021021414423848.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)若需打包windows平台,则需要额外安装wine组件。笔者按wine官网的标准方式安装,未能成功,后参照[此贴](https://askubuntu.com/questions/1164191/wine-staging-fails-to-install-on-18-04)安装成功,推测安装失败的原因可能与WSL2有关。其步骤如下:
```
sudo apt-get purge *wine*
sudo snap remove wine
sudo snap update wine-platform-*
grep -Ril "wine" /etc/apt
sudo dpkg --add-architecture i386
wget -nc https://dl.winehq.org/wine-builds/winehq.key
sudo apt-key add winehq.key
sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main'
sudo apt update
sudo apt upgrade
sudo apt --fix-broken install
sudo apt autoremove --purge
sudo apt upgrade
wget https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/Release.key
sudo apt-key add Release.key
sudo apt-add-repository 'deb https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/ ./'
sudo apt update
sudo apt install libfaudio0 libasound2-plugins:i386 -y
sudo apt install --install-recommends winehq-stable -y
```
#### icongenie图片生成工具安装
按[文档](https://quasar.dev/icongenie/installation)进行安装时,出现报错,原因在于其中sharp包的依赖libvips安装失败。手动安装libvips,直接使用apt安装后无效,故对libvips进行编译安装
在https://github.com/libvips/libvips/releases下载源代码,按照https://libvips.github.io/libvips/install.html进行编译、安装。
#### 开发工具配置
推荐使用VScode通过wsl-remote插件直接访问wsl容器,并安装Vetur插件对.vue单文件组件提供支持,安装Vue VSCode Snippets加速开发,安装Eslint提供静态代码分析,安装prettier格式化和工具配合Eslint提供代码格式化。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210214145038731.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)打开项目文件夹/.vscode/settings.json,添加对项目格式化引擎等选项的配置(仅对本工程生效):
```
{
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": false,
"javascript.format.placeOpenBraceOnNewLineForFunctions": false,
"typescript.format.insertSpaceBeforeFunctionParenthesis": true,
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": false,
"typescript.format.placeOpenBraceOnNewLineForFunctions": false,
"vetur.format.defaultFormatter.html": "prettyhtml",
"vetur.format.defaultFormatter.js": "prettier-eslint"
}
```
vscode的prettier插件和eslint插件的配置方法见:[here](https://blog.echobind.com/integrating-prettier-eslint-airbnb-style-guide-in-vscode-47f07b5d7d6a)。
#### 项目工程结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210217110005329.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)其中比较重要的是如下几个目录:
1. /quasar.conf.js 填写quasar框架的配置信息,如,当要使用quasar的对话框插件,需在该文件中添加配置项。
2. /src/router 填写vue router的路由规则
3. /src/layouts 存放描述layouts的.vue文件,该文件描述页面的整体布局(侧边栏,工具栏位置)
4. /src/pages 存放页面,会通过vue路由渲染到/src/layouts/xxx.vue
5. /src/store 存放vuex
6. /src/assets 存放webpack处理的静态资源。这里存放的图片等资源会被wenpack打包处理(如进行base64转换后嵌入js代码),要引用此处存放的资源,应使用
```
<img src="~assets/logo.png">
```
7. /public 存放静态资源,不被wenpack处理,仅进行复制,故icon等资源一般存放在此处,调用方法如下:
```
<img src="logo.png">
<img src="/logo.png">
```
8. /src-electron 存放electron的配置文件和main thread逻辑
9. /dist/xxx 存放各模式下编译出来的目标文件
## Quasar框架
这里摘录一些Quasar框架常用的功能和组件。
### 实用的css样式类
[字体样式控制](https://quasar.dev/style/typography#Introduction):提供对文本的字体、字号、加粗、斜体、对齐方式的控制。如,对文本加粗,并居中对齐:
```
<div class="text-body1 text-weight-bold text-center">Hello Quasar</div>
```
#### 颜色系统
[颜色系统](https://quasar.dev/style/color-palette#Introduction)提供了一套主题色和标准色,通过添加text-xxx类,可以变更文字颜色,通过bg-xxx可更换背景色:
```
<div class="text-body1 text-weight-bold text-center text-primary bg-positive">Hello Quasar</div>
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210215124907713.png)[Theme builder](https://quasar.dev/style/theme-builder#Theme-Builder)提供快速配置主题色号的功能。
#### Spacing系统
Spacing是指dom元素之间的间隔方式:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021021512514170.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)[quasar spacing系统](https://quasar.dev/style/spacing#Introduction) 提供一组css类完成spacing工作,具体的像素数会随着响应式系统自动变化,这组类的命名规则如下:
```
q-[p|m][t|r|b|l|a|x|y]-[none|auto|xs|sm|md|lg|xl]
T D S
T - type
- values: p (padding), m (margin)
D - direction
- values:
t (top), r (right), b (bottom), l (left),
a (all), x (both left & right), y (both top & bottom)
S - size
- values:
none,
auto (ONLY for specific margins: q-ml-*, q-mr-*, q-mx-*),
xs (extra small),
sm (small),
md (medium),
lg (large),
xl (extra large)
# 例如
<div class="q-pa-sm">...</div>
```
#### 显示控制
[显示控制css类组](https://quasar.dev/style/visibility#Introduction)用于控制dom元素的显示情况。部分css类的效果如下:
1. disabled 表示禁止选中
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210216120025833.png)
2. hidden 表示隐藏该元素
3. invisible 将元素设为不可见,但仍占据原有位置
4. transparent 将组件背景色变为透明(删去背景色)
5. ellipsis ellipsis-2-lines ellipsis-3-lines 将显示不下的长文本省略并在末尾添加省略号
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210216124532741.png)
此外,[显示控制css类组](https://quasar.dev/style/visibility#Introduction)还提供根据window宽度和应用所处的运行平台(手机、pad、桌面端)隐藏和显示组件的功能。
#### 实用辅助类
[这些css类](https://quasar.dev/style/other-helper-classes#Introduction)实现了对鼠标选中的控制,滑动的控制,尺寸控制等待。
### 动画
[Animations](https://quasar.dev/options/animations#Introduction)提供了对vue** **[Transition](https://vuejs.org/v2/guide/transitions.html#Custom-Transition-Classes) 机制和css动效库[Animate.css](https://animate.style/)的封装,使用方法如下:
1. 在/quasar.conf.js中开启Animate.css:
```
animations: 'all'
animations: [
'bounceInLeft',
'bounceOutRight'
]
```
2. 使用transition组件包裹需要施加动画的部分
```
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<p v-if="show">hello</p>
</transition>
```
其中动画选项有六种(实际仅enter-active-class和leave-active-class常用):
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
3. 改变组件绑定的show属性,可看到动画效果。
### 布局系统
Quasar的布局系统基于[Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)开发,通过Container (Parent)和items (Children)两个层级管理容器中的组件,提供对组件在不同尺寸下排列的方式、位置、间距的精细化控制:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210216152637766.png)例如,
```
<div class="row">
<div class="col-8">two thirds</div>
<div class="col-2">one sixth</div>
<div class="col-auto">auto size based on content and available space</div>
<div class="col">fills remaining available space</div>
</div>
```
其中class="row"是Parent层级,有如下可选类型:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210218094824273.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)最常用的是row(横向),column(纵向)。
使用justify类和items-xxx类可控制Parent下子组件横向、纵向的对齐方式:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210218095155722.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20210218095756710.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
对与Parent中每个Children组件,“col-xxx” 类用于控制组件的宽(高),Parent被等分为12个块,可使用“col-1”,“col-2”…指定宽高,或使用“col-auto”令Children适应组件内容的形状,“col”则表示指定组件宽为Parent剩余的全部位置。offset-xxx可控制位置的偏置量。
除文档外,Quasar提供[flex-playground](https://quasar.dev/layout/grid/flex-playground#Introduction)帮助用户理解样式的具体效果。
一个例子如下,对组件指定了背景色以更加清楚的显示其占位。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219110732142.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
```
<template>
<q-page class="q-pa-md column bg-green-2 justify-center items-center">
<div class="col-auto bg-grey-2">
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<img v-if="show" alt="Quasar logo" src="~assets/quasar-logo-full.svg" />
</transition>
</div>
<div class="col-auto bg-grey-4">
<q-btn color="secondary" label="Show" @click="show = !show" />
</div>
</q-page>
</template>
```
q-page是整个页面的根组件,q-page是页面路由要求使用的。对其添加column使之成为flex布局的parent组件,justify-center items-center使得内部元素垂直居中+水平居中。两个子组件指定col-auto类,以自适应组件内容,否则会有留白,如:将col-auto替换为col(表示填满空间)的效果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219111059658.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
### Layout
QLayout是一个组件,用于管理整个窗口并使用导航栏或抽屉等元素包装页面内容,是对布局系统的一层封装,可以帮助更好地构建网站/应用程序。使用[layout builder](https://quasar.dev/layout-builder)可快速定制一个布局方案。如:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021021621325420.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)builder生成的代码应填写到/src/layouts/MainLayout.vue路径。对其中的header footer和侧边栏属性的详细控制可在文档中找到。
### 组件库
Quasar提供了海量的vue组件([组件是可复用的 Vue 实例,详见vue文档](https://cn.vuejs.org/v2/guide/components.html)),文档中,每个组件有四类API:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210216221349560.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
probs是传入组件的属性,例如向QAjaxBar组件传入skip-hijack等属性,可写作:
```
<q-ajax-bar
position="bottom"
color="accent"
size="10px"
skip-hijack
/>
```
events是组件能够发出的事件。组件事件用于如下场景([摘自vue文档](https://cn.vuejs.org/v2/guide/components.html#%E7%9B%91%E5%90%AC%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BA%8B%E4%BB%B6)):
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210216221116421.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)slots用于指定组件分发内容([文档](https://cn.vuejs.org/v2/guide/components.html#%E9%80%9A%E8%BF%87%E6%8F%92%E6%A7%BD%E5%88%86%E5%8F%91%E5%86%85%E5%AE%B9))。注意[具名插槽](https://cn.vuejs.org/v2/guide/components-slots.html#%E5%85%B7%E5%90%8D%E6%8F%92%E6%A7%BD)的使用,具名插槽机制可令组件接收多个输入插槽。在向具名插槽提供内容的时候,我们可以在一个 template元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:
```
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
```
methods是组件提供的分发,通过设置组件的ref属性,我们可通过this.\$refs对组件进行索引,进而调用组件方法([vue文档](https://cn.vuejs.org/v2/guide/components-edge-cases.html#%E8%AE%BF%E9%97%AE%E5%AD%90%E7%BB%84%E4%BB%B6%E5%AE%9E%E4%BE%8B%E6%88%96%E5%AD%90%E5%85%83%E7%B4%A0)):
如:
```
<base-input ref="usernameInput"></base-input>
```
```
this.$refs.usernameInput.xxx()
```
### 插件
某些功能需要通过[插件](https://quasar.dev/quasar-plugins/)的方式实现,如对话框、通知、全屏触发等常用功能。
### utils
[utils](https://quasar.dev/quasar-utils/)中提供了一些实用的函数,如格式化显示日期、时间,下载触发、url跳转、复制到剪贴板、api触发频率限制、uid生成、对象深拷贝等。
### 页面路由
页面路由是单页应用的重要环节,quasar项目集成vue-router支持。在src/layouts/MainLayout.vue中使用q-route-tab编写路由接口:
```
<q-tabs v-model="tab" align="left">
<q-route-tab to="/" label="index" />
<q-route-tab to="/testpage" label="testpage" />
</q-tabs>
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219143723948.png)在src/router/routes.js中填写路由映射:
```
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/Index.vue') },
{ path: 'testpage', component: () => import('pages/TestPage.vue') },
],
},
```
在/src/pages目录下放置页面:
```
<template>
<q-page class="flex flex-center">
<h1>{{ foo }}</h1>
</q-page>
</template>
<script>
export default {
name: 'PageTestPage',
data() {
return {
foo: 'this is testpage',
};
},
};
</script>
```
### vuex
quaser项目也提供了对vuex的支持(可选),Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,用于解决多组件之间的共享状态问题。在单页app中,vuex典型的应用场景是同步多个页面之间的状态。在vuex的设计中,通过mutation(一组函数)来变更状态(state),配合vue的计算属性机制,多个页面的组件之间可响应式的共享state的值。![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219165716293.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)quaser中,使用[vuex-模块](https://vuex.vuejs.org/zh/guide/modules.html)进行组织,更易于维护。![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219165831148.png)其中每个模块文件夹包含如下文件:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219165905297.png)使用cli可以代替手动复制,快速新建一个模块:
```
quasar new store <store_name>
```
下面举例说明如何使用vuex在两个页面之间同步状态。
命令行执行quasar new store showcase生成一个新的showcase模块,编辑src/store/index.js引入新模块:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219170324933.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)编辑src/store/showcase/state.js定义两个欲进行同步的状态drawerState、message:
```
export default function () {
return {
drawerState: true,
message: '',
};
}
```
编辑src/store/showcase/mutations.js编写修改状态的方法:
```
export const updateDrawerState = (state, opened) => {
state.drawerState = opened;
};
export const updateMessageState = (state, msg) => {
state.message = msg;
};
```
在页面组件中使用:
页面1:index.vue
```
<template>
<q-page class="q-pa-md column justify-center items-center q-gutter-md">
<div class="col-auto">
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<img v-if="show" alt="Quasar logo" src="~assets/quasar-logo-full.svg" />
</transition>
</div>
<div class="col-auto">
<q-btn color="secondary" label="Show" @click="show = !show" />
</div>
<div class="col-auto">
{{ drawerState }}
<q-toggle v-model="drawerState" />
<q-btn color="secondary" label="Update" @click="updateMsg" />
</div>
</q-page>
</template>
<script>
import { date } from 'quasar';
export default {
name: 'PageIndex',
data() {
return {
show: true,
};
},
methods: {
updateMsg() {
const { addToDate } = date;
const newDate = addToDate(new Date(), { days: 7, month: 1 });
this.$store.commit('showcase/updateMessageState', newDate);
},
},
computed: {
drawerState: {
get() {
return this.$store.state.showcase.drawerState;
},
set(val) {
this.$store.commit('showcase/updateDrawerState', val);
},
},
},
};
</script>
```
页面2:testpage.vue:
```
<template>
<q-page class="flex flex-center">
<q-toggle v-model="drawerState" />
<p>{{ msgState }}</p>
</q-page>
</template>
<script>
export default {
name: 'PageTestPage',
data() {
return {
foo: 'this is testpage',
};
},
computed: {
drawerState: {
get() {
return this.$store.state.showcase.drawerState;
},
set(val) {
this.$store.commit('showcase/updateDrawerState', val);
},
},
msgState() {
return this.$store.state.showcase.message;
},
},
};
</script>
```
通过定义计算属性的get,可以在this.\$store.state被变更时自动刷新dom渲染。对状态的变更则一律通过this.\$store.commit调用src/store/showcase/mutations.js中编写的修改状态的方法来实现。效果如下,两个页面的开关状态同步,页面1update变更状态可以在页面2体现:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219171109760.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20210219171116315.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)
### electron nodejs api调用
对于添加了electron模块的quasar项目,quasar生成项目时已经进行了相关配置,故可在前端代码直接使用nodejs的模块。
### api调用
Axios是一个基于promise 的著名HTTP库,如在生成工程时选择添加axios,则会在src/boot/axios.js中将axios库挂载到Vue.prototype.\$axios,.vue文件中使用 this.\$axios可访问它。典型使用如下:
```
this.$axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => {
this.info = response.data.bpi
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
```
注:例子中的coindesk api是一个支持跨域访问的比特币行情api。
注意,不同于jsonp,axios是无法单方面解决跨域问题的,需要接口配合。如,使用python flask写个api接口,可通过cross\_origin库添加跨域许可:
```
from flask import Flask, request
from flask_cors import cross_origin
app = Flask(__name__)
@app.route('/hello')
@cross_origin(resources=r'/*')
def hello():
return "hello"
if __name__ == '__main__':
app.run(host='192.168.3.16',port=5000,debug=True)
```
此处服务端使用本机真实IP地址,若使用127.0.0.1,则在electron打包的app中,axios报错(xhr),从axios 的github讨论来看,可能是一个bug。关于IP、localhost、127.0.0.1的区别可参考[此文](https://blog.csdn.net/mengzuchao/article/details/81462958)。
### echart图表
echart是百度开发的前端图表库,已经捐助到apache基金会。
直接使用原生的Echart库,参考文章[vue中使用ECharts实现折线图和饼图](https://segmentfault.com/a/1190000022096665)。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210220195127728.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaWRhX3d0,size_16,color_FFFFFF,t_70)src/pages/echartDemo.vue:
```
<template>
<q-page class="flex flex-center">
<div ref="chartPie" class="pie-wrap"></div>
</q-page>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'echartDemo',
data() {
return {
chartPie: null,
};
},
mounted() {
this.$nextTick(() => {
this.drawPieChart();
});
},
methods: {
drawPieChart() {
const mytextStyle = {
color: '#333',
fontSize: 18,
};
const mylabel = {
show: true,
position: 'right',
offset: [30, 40],
formatter: '{b} : {c} ({d}%)',
textStyle: mytextStyle,
};
this.chartPie = echarts.init(this.$refs.chartPie);
this.chartPie.setOption({
title: {
text: 'Pie Chart',
subtext: '纯属虚构',
x: 'center',
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)',
},
legend: {
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'],
left: 'center',
top: 'bottom',
orient: 'horizontal',
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['50%', '70%'],
center: ['50%', '50%'],
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' },
],
animationEasing: 'cubicInOut',
animationDuration: 2600,
label: {
emphasis: mylabel,
},
},
],
});
},
},
};
</script>
<style>
.pie-wrap {
width: 100%;
height: 400px;
}
</style>
```
其中, 触发绘制的函数drawPieChart被挂载到mounted(),根据vue生命周期钩子的描述,mounted()将在dom渲染完毕后执行。使用this.\$nextTick方法可以使得dom刷新后drawPieChart再被触发。
### 组件化开发
对于重复的逻辑,可以抽离并编写成自定义组件,提升代码的可维护性。举例来说,构建一个折线图组件,接收x轴图例数组和y轴数据两个属性,渲染一个折线图。
工程的组件放在src/components目录。编辑src/components/EchartsCategory.vue,编写组件:
```
<template>
<div ref="chart" class="chart"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'EchartsCategory',
components: {},
data() {
return {
myChart: null,
};
},
props: {
xAxisdata: {
type: Array,
default() {
return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
},
},
yAxisdata: {
type: Array,
default() {
return [150, 230, 224, 218, 135, 147, 260];
},
},
},
mounted() {
this.$nextTick(() => {
this.draw();
});
},
methods: {
draw() {
this.myChart = echarts.init(this.$refs.chart);
this.myChart.setOption({
xAxis: {
type: 'category',
data: this.xAxisdata,
},
yAxis: {
type: 'value',
},
series: [
{
data: this.yAxisdata,
type: 'line',
},
],
});
},
},
};
</script>
<style>
.chart {
width: 100%;
height: 400px;
}
</style>
```
其中props定义了组件可接收的属性的规格和默认值。
在src/pages/echartDemo.vue中使用EchartsCategory这一组件:
```
<template>
<q-page class="flex flex-center">
<EchartsCategory v-bind="EchartsCategoryData"></EchartsCategory>
</q-page>
</template>
<script>
import EchartsCategory from 'components/EchartsCategory.vue';
export default {
name: 'echartDemo',
components: { EchartsCategory },
data() {
return {
EchartsCategoryData: {
xAxisdata: ['abc', 'def', 'sdsd'],
yAxisdata: [12, 35, 76],
},
};
},
};
</script>
```
使用import引入组件后,需在components中加以引用。对EchartsCategory 组件添加v-bind,将props整体传入,这和如下写法是等效的:
```
<EchartsCategory
v-bind:xAxisdata="EchartsCategoryData.xAxisdata"
v-bind:yAxisdata="EchartsCategoryData.yAxisdata">
</EchartsCategory>
```
文章知识点与官方知识档案匹配,可进一步学习相关知识
评论
已自动恢复阅读位置、日/夜间模式参数