3.Vue项目实战
1. 前端项目技术栈
- Vue
- Vue-router
- Element-UI
- Axios
- Echarts
2. 后端项目技术栈
- Node.js
- Express
- Jwt
- Mysql
- Sequelize
1.创建项目
1.1创建时候选择babel和vue-router(eslint验证就不选了)

为了方便,选择图形化界面来管理。 vue ui
1.2配置Element-UI。点击插件->添加插件
vue/cli-plugin-element
UN.png)
1.2.1选择按需导入

1.2.2用图形化界面会自动创建好element-ui相关配置
如果自己在命令行安装,需要
src->plugins->element.js
1 2 3 4
| import Vue from 'vue' import { Button } from 'element-ui'
Vue.use(Button)
|
main.js
1
| import './plugins/element.js'
|

1.3配置axios库
依赖->安装依赖->运行依赖->axios

1.4初始化git仓库,提交项目到仓库
1.5安装sass,和sass-loader 选择开发依赖
1 2
| "sass": "^1.53.0", "sass-loader": "^8.0.2",
|

1.6修改图标
在public下替换favicon.ico
2.登录功能
2.1. 登录业务流程
① 在登录页面输入用户名和密码
② 调用后台接口进行验证
③ 通过验证之后,根据后台的响应状态跳转到项目主页
2.2. 登录业务的相关技术点
http 是无状态的
通过 cookie 在客户端记录状态
通过 session 在服务器端记录状态
通过 token 方式维持状态(跨域用)
2.3token原理
截一张黑马的图

创建分支
git checkout -b ‘分支名称’
2.4配置axios
main.js
1 2 3
| import axios from 'axios' axios.defaults.baseURL = "http://localhost:8080" Vue.prototype.$http = axios
|
3.表格导出为excel
3.1安装插件
1
| npm install --save xlsx file-saver
|
3.2在相关vue文件中引入插件
1 2
| import FileSaver from 'file-saver' import * as XLSX from 'xlsx'
|
3.3编写导出方法
3.3.1导出函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| exportExcel () { var xlsxParam = { raw: true } var table = document.querySelector('#exportTab').cloneNode(true) var wb = XLSX.utils.table_to_book(table, xlsxParam) var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' }) try { FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'fileName.xlsx') } catch (e) { if (typeof console !== 'undefined') { console.log(e, wbout) } } return wbout }
|
3.3.2表格内容

3.3.3导出示意图

5.树形table表格(插件)

1 2 3 4
| import Vue from 'vue' import ZkTable from 'vue-table-with-tree-grid'
Vue.use(ZkTable)
|
或者
1 2 3 4
| import Vue from 'vue' import ZkTable from 'vue-table-with-tree-grid'
Vue.component(ZkTable.name, ZkTable)
|
地址:https://github.com/MisterTaki/vue-table-with-tree-grid
实战使用:main.js
1 2 3
| import TreeTable from 'vue-table-with-tree-grid'
Vue.component('tree-table', TreeTable)
|
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 29 30 31 32 33 34 35 36 37 38
| <tree-table :data="catesList" show-index :expand-type="false" :selection-type="false" :columns="columns" border > <template slot="isok" slot-scope="scope"> <i class="el-icon-success" v-if="scope.row.cat_deleted == false" style="color: lightgreen" ></i> <i class="el-icon-error" v-else style="color: red"></i> </template> <template slot="order" slot-scope="scope"> <el-tag v-if="scope.row.cat_level == 0" size="mini">一级</el-tag> <el-tag v-else-if="scope.row.cat_level == 1" type="success" size="mini" >二级</el-tag > <el-tag v-else type="warning" size="mini">三级</el-tag> </template> <template slot="opt" slot-scope="scope"> <el-button :hidden="scope" type="primary" icon="el-icon-edit" size="mini" >编辑</el-button > <el-button type="danger" icon="el-icon-delete" size="mini" >删除</el-button > </template> </tree-table>
|
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
| data(){ return { columns: [ { label: '分类名称', prop: 'cat_name', }, { label: '是否有效', type: 'template', template: 'isok', }, { label: '排序', type: 'template', template: 'order', }, { label: '操作', type: 'template', template: 'opt', } ], } }
|
6.进度条(nprogress)
安装
1
| npm install --save nprogress
|
或者

使用:main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import NProgress from 'nprogress' import 'nprogress/nprogress.css'
axios.interceptors.request.use(config => { NProgress.start() config.headers.Authorization = window.sessionStorage.getItem('token') return config })
axios.interceptors.response.use(config => { NProgress.done() return config })
|
安装
1
| npm install babel-plugin-transform-remove-console --save-dev
|
或者

使用
1 2 3 4 5 6 7 8 9
| { "plugins": ["transform-remove-console"] } Copy
{ "plugins": [["transform-remove-console", { "exclude": ["error", "warn"] }]] }
|
使用babel.config.js
1
| 'transform-remove-console'
|

这样使用,会在开发时候也把console.log()给移除掉
推荐这样来写
babel.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const prodPlugins = [] if(process.env.NODE_ENV === 'production') { prodPlugins.push('transform-remove-console') } module.exports = { "presets": [ "@vue/cli-plugin-babel/preset" ], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ], ...prodPlugins ] }
|
8.项目优化策略










main.js复制为main-dev.js和main-prod.js
在main.prod.js中可以删去引用nprogress的css和富文本编辑器的css,删除按需导入的element-ui
public->index.html
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
| <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title><%= htmlWebpackPlugin.options.isProd?'':'dev-'%>电商后台管理系统</title> <% if(htmlWebpackPlugin.options.isProd){%> <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" /> <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" /> <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" /> <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" /> <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/themechalk/index.css" />
<script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js"></script> <script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js"></script> <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script> <script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js"></script> <script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js"></script> <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script> <script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script> <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script> <% } %>
|
vue.config.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
| module.exports = { chainWebpack: config => { config.when(process.env.NODE_ENV === 'production',config=>{ config.entry('app').clear().add('./src/main-prod.js') config.set('externals',{ Vue:'Vue', 'Vue-router':'VueRouter', axios:'axios', lodash:'_', echarts:'echarts', nprogress:'NProgress', 'vue-quill-editor':'VueQuillEditor' }) config.plugin('html').tap(args=>{ args[0].isProd = true return args }) }) config.when(process.env.NODE_ENV === 'development',config=>{ config.entry('app').clear().add('./src/main-dev.js') config.plugin('html').tap(args=>{ args[0].isProd = false return args }) }) } }
|


index.html配置
可以实现组件的懒加载分组打包


webpackChunkName名字是懒加载分组名称

9.项目上线相关配置
通过node创建web服务器。(运行 node app.js)
app.js代码如下

开启gzip配置。
app.js中


配置https服务。


使用pm2管理应用。
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const express = require('express') const compression = require('compression') const https = require('https') const fs = require('fs') const app = express()
const options = { cert: fs.readFileSync('./full_chain.pem'), key: fs.readFileSync('./private.key') }
app.use(compression()) app.use(express.static('./dist'))
app.listen(80, () => { console.log('server running at http://127.0.0.1') })
|
服务器目录结构


在服务器中安装pm2:
启动项目:
1 2
| pm2 start 脚本 --name 自定义名称 pm2 start ./app.js --name web_vueshop
|
查看运行项目: pm2 ls
重启项目:pm2 restart 自定义名称 (自定义名称中可以使用id)
停止项目: pm2 stop 自定义名称
删除项目: pm2 delete 自定义名称

10.Echarts的使用
10.1 安装
1
| npm install echarts --save
|

10.2 使用
10.2.1 在需要使用的vue文件中引入
1 2
| import * as echarts from 'echarts' import geoJson from '../../assets/js/hk'
|
10.2.2 定义变量option
1 2 3 4 5 6 7
| data() { return { option: { }, } }
|
102.3 定义获取方法
1 2 3 4 5 6 7 8 9 10 11 12
| methods: { async showMap() { var chartDom = document.getElementById('main') var myChart = echarts.init(chartDom) echarts.registerMap('HK', geoJson) myChart.setOption(this.option) this.option && myChart.setOption(this.option) }, }
|
10.2.4 在页面渲染之前调用
1 2 3
| mounted() { this.showMap() },
|
10.注意点:
10.1 :src引入本地图片问题
:src动态获取图片时,需要给图片的路径加require,否则图片不会显示
1 2 3 4 5
| { path: require('../assets/img/vue.svg'), name: 'Vue', desc: '渐进式JavaScript 框架', }
|
11.富文本编辑器
说在前头
值得注意的是按需引入使用,需要十分清楚你所使用的编辑器主题、皮肤和插件,当你设置的编辑器主题、皮肤和插件没有正确引入导致编辑器无法显示。
如果使用场景是管理后台,建议使用全局引入的方式来使用,编辑器主题、皮肤和插件将会自动按需加载,相对引入式使用会来得方便和灵活。
目录
全局引入
例子入口
第一步,安装
1
| npm i tinymce @packy-tang/vue-tinymce
|
第二步,搬运
复制node_modules/tinymce
目录下所有文件至public/
目录下
1
| cp node_modules/tinymce/ public/
|
复制后大概是这样的
然后在public/index.html
页面全局引入tinymce
1 2 3 4 5
| <div id="app"></div> <script src="./tinymce/tinymce.min.js"></script> </body> </html>
|
全局引入的本地化处理
将zh_CN.js
文件直接放到public/tinymce/langs/
目录下就可以了,配置时加上{language: 'zh_CN'}
的设置就能实现。
第三步,引入并安装插件
1 2 3 4 5 6 7
| import Vue from 'vue' import App from './App.vue' import tinymce from 'tinymce' import VueTinymce from '@packy-tang/vue-tinymce'
Vue.prototype.$tinymce = tinymce Vue.use(VueTinymce)
|
具体看main.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
| <template> <div id="app"> <div id="logo"> <img alt="Vue+Tinymce" src="https://raw.githubusercontent.com/lpreterite/vue-tinymce/HEAD/docs/assets/vu-tinymce-logo.png"> </div> <vue-tinymce v-model="content" :setting="setting" /> </div> </template>
<script> export default { name: 'app', data(){ return { content: '<h1 style="text-align: center;">长恨歌</h1><p style="text-align: center;">汉皇重色思倾国,御宇多年求不得。<br />杨家有女初长成,养在深闺人未识。<br />天生丽质难自弃,一朝选在君王侧。<br />回眸一笑百媚生,六宫粉黛无颜色。<br />春寒赐浴华清池,温泉水滑洗凝脂。<br />侍儿扶起娇无力,始是新承恩泽时。<br />云鬓花颜金步摇,芙蓉帐暖度春宵。<br />春宵苦短日高起,从此君王不早朝。<br />承欢侍宴无闲暇,春从春游夜专夜。<br />后宫佳丽三千人,三千宠爱在一身。<br />金屋妆成娇侍夜,玉楼宴罢醉和春。<br />姊妹弟兄皆列土,可怜光彩生门户。<br />遂令天下父母心,不重生男重生女。<br />骊宫高处入青云,仙乐风飘处处闻。<br />缓歌慢舞凝丝竹,尽日君王看不足。<br />渔阳鼙鼓动地来,惊破霓裳羽衣曲。</p><p style="text-align: center;">九重城阙烟尘生,千乘万骑西南行。<br />翠华摇摇行复止,西出都门百余里。<br />六军不发无奈何,宛转蛾眉马前死。<br />花钿委地无人收,翠翘金雀玉搔头。<br />君王掩面救不得,回看血泪相和流。<br />黄埃散漫风萧索,云栈萦纡登剑阁。<br />峨嵋山下少人行,旌旗无光日色薄。<br />蜀江水碧蜀山青,圣主朝朝暮暮情。<br />行宫见月伤心色,夜雨闻铃肠断声。<br />天旋日转回龙驭,到此踌躇不能去。<br />马嵬坡下泥土中,不见玉颜空死处。<br />君臣相顾尽沾衣,东望都门信马归。<br />归来池苑皆依旧,太液芙蓉未央柳。<br />芙蓉如面柳如眉,对此如何不泪垂。<br />春风桃李花开夜,秋雨梧桐叶落时。<br />西宫南苑多秋草,落叶满阶红不扫。<br />梨园弟子白发新,椒房阿监青娥老。<br />夕殿萤飞思悄然,孤灯挑尽未成眠。<br />迟迟钟鼓初长夜,耿耿星河欲曙天。<br />鸳鸯瓦冷霜华重,翡翠衾寒谁与共。<br />悠悠生死别经年,魂魄不曾来入梦。</p><p style="text-align: center;">临邛道士鸿都客,能以精诚致魂魄。<br />为感君王辗转思,遂教方士殷勤觅。<br />排空驭气奔如电,升天入地求之遍。<br />上穷碧落下黄泉,两处茫茫皆不见。<br />忽闻海上有仙山,山在虚无缥缈间。<br />楼阁玲珑五云起,其中绰约多仙子。<br />中有一人字太真,雪肤花貌参差是。<br />金阙西厢叩玉扃,转教小玉报双成。<br />闻道汉家天子使,九华帐里梦魂惊。<br />揽衣推枕起徘徊,珠箔银屏迤逦开。<br />云鬓半偏新睡觉,花冠不整下堂来。</p><p style="text-align: center;">风吹仙袂飘飖举,犹似霓裳羽衣舞。<br />玉容寂寞泪阑干,梨花一枝春带雨。<br />含情凝睇谢君王,一别音容两渺茫。<br />昭阳殿里恩爱绝,蓬莱宫中日月长。<br />回头下望人寰处,不见长安见尘雾。<br />惟将旧物表深情,钿合金钗寄将去。<br />钗留一股合一扇,钗擘黄金合分钿。<br />但令心似金钿坚,天上人间会相见。</p><p style="text-align: center;">临别殷勤重寄词,词中有誓两心知。<br />七月七日长生殿,夜半无人私语时。<br />在天愿作比翼鸟,在地愿为连理枝。<br />天长地久有时尽,此恨绵绵无绝期。</p>', setting: { menubar: false, toolbar: "undo redo | fullscreen | formatselect alignleft aligncenter alignright alignjustify | link unlink | numlist bullist | image media table | fontselect fontsizeselect forecolor backcolor | bold italic underline strikethrough | indent outdent | superscript subscript | removeformat |", toolbar_drawer: "sliding", quickbars_selection_toolbar: "removeformat | bold italic underline strikethrough | fontsizeselect forecolor backcolor", plugins: "link image media table lists fullscreen quickbars", language: 'zh_CN', //本地化设置 height: 350 } } } } </script>
|
按需引入
例子入口
第一步,安装
1
| npm i tinymce @packy-tang/vue-tinymce
|
第二步,引入文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| //
//样式 import 'tinymce/skins/content/default/content.min.css' import 'tinymce/skins/ui/oxide/skin.min.css' import 'tinymce/skins/ui/oxide/content.min.css'
//主题 import 'tinymce/themes/silver'
//插件 import 'tinymce/plugins/link' //链接插件 import 'tinymce/plugins/image' //图片插件 import 'tinymce/plugins/media' //媒体插件 import 'tinymce/plugins/table' //表格插件 import 'tinymce/plugins/lists' //列表插件 import 'tinymce/plugins/quickbars' //快速栏插件 import 'tinymce/plugins/fullscreen' //全屏插件
|
注:5.3.x版本需要额外引进图标,没有所有按钮就会显示not found
1
| import 'tinymce/icons/default/icons'
|
本地化
1 2
| import './utils/tinymce/langs/zh_CN.js'
|
具体看这个文件main.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
| <template> <div id="app"> <div id="logo"> <img alt="Vue+Tinymce" src="https://raw.githubusercontent.com/lpreterite/vue-tinymce/HEAD/docs/assets/vu-tinymce-logo.png"> </div> <vue-tinymce v-model="content" :setting="setting" /> </div> </template>
<script> export default { name: 'app', data(){ return { content: '<h1 style="text-align: center;">长恨歌</h1><p style="text-align: center;">汉皇重色思倾国,御宇多年求不得。<br />杨家有女初长成,养在深闺人未识。<br />天生丽质难自弃,一朝选在君王侧。<br />回眸一笑百媚生,六宫粉黛无颜色。<br />春寒赐浴华清池,温泉水滑洗凝脂。<br />侍儿扶起娇无力,始是新承恩泽时。<br />云鬓花颜金步摇,芙蓉帐暖度春宵。<br />春宵苦短日高起,从此君王不早朝。<br />承欢侍宴无闲暇,春从春游夜专夜。<br />后宫佳丽三千人,三千宠爱在一身。<br />金屋妆成娇侍夜,玉楼宴罢醉和春。<br />姊妹弟兄皆列土,可怜光彩生门户。<br />遂令天下父母心,不重生男重生女。<br />骊宫高处入青云,仙乐风飘处处闻。<br />缓歌慢舞凝丝竹,尽日君王看不足。<br />渔阳鼙鼓动地来,惊破霓裳羽衣曲。</p><p style="text-align: center;">九重城阙烟尘生,千乘万骑西南行。<br />翠华摇摇行复止,西出都门百余里。<br />六军不发无奈何,宛转蛾眉马前死。<br />花钿委地无人收,翠翘金雀玉搔头。<br />君王掩面救不得,回看血泪相和流。<br />黄埃散漫风萧索,云栈萦纡登剑阁。<br />峨嵋山下少人行,旌旗无光日色薄。<br />蜀江水碧蜀山青,圣主朝朝暮暮情。<br />行宫见月伤心色,夜雨闻铃肠断声。<br />天旋日转回龙驭,到此踌躇不能去。<br />马嵬坡下泥土中,不见玉颜空死处。<br />君臣相顾尽沾衣,东望都门信马归。<br />归来池苑皆依旧,太液芙蓉未央柳。<br />芙蓉如面柳如眉,对此如何不泪垂。<br />春风桃李花开夜,秋雨梧桐叶落时。<br />西宫南苑多秋草,落叶满阶红不扫。<br />梨园弟子白发新,椒房阿监青娥老。<br />夕殿萤飞思悄然,孤灯挑尽未成眠。<br />迟迟钟鼓初长夜,耿耿星河欲曙天。<br />鸳鸯瓦冷霜华重,翡翠衾寒谁与共。<br />悠悠生死别经年,魂魄不曾来入梦。</p><p style="text-align: center;">临邛道士鸿都客,能以精诚致魂魄。<br />为感君王辗转思,遂教方士殷勤觅。<br />排空驭气奔如电,升天入地求之遍。<br />上穷碧落下黄泉,两处茫茫皆不见。<br />忽闻海上有仙山,山在虚无缥缈间。<br />楼阁玲珑五云起,其中绰约多仙子。<br />中有一人字太真,雪肤花貌参差是。<br />金阙西厢叩玉扃,转教小玉报双成。<br />闻道汉家天子使,九华帐里梦魂惊。<br />揽衣推枕起徘徊,珠箔银屏迤逦开。<br />云鬓半偏新睡觉,花冠不整下堂来。</p><p style="text-align: center;">风吹仙袂飘飖举,犹似霓裳羽衣舞。<br />玉容寂寞泪阑干,梨花一枝春带雨。<br />含情凝睇谢君王,一别音容两渺茫。<br />昭阳殿里恩爱绝,蓬莱宫中日月长。<br />回头下望人寰处,不见长安见尘雾。<br />惟将旧物表深情,钿合金钗寄将去。<br />钗留一股合一扇,钗擘黄金合分钿。<br />但令心似金钿坚,天上人间会相见。</p><p style="text-align: center;">临别殷勤重寄词,词中有誓两心知。<br />七月七日长生殿,夜半无人私语时。<br />在天愿作比翼鸟,在地愿为连理枝。<br />天长地久有时尽,此恨绵绵无绝期。</p>', setting: { menubar: false, toolbar: "undo redo | fullscreen | formatselect alignleft aligncenter alignright alignjustify | link unlink | numlist bullist | image media table | fontselect fontsizeselect forecolor backcolor | bold italic underline strikethrough | indent outdent | superscript subscript | removeformat |", toolbar_drawer: "sliding", quickbars_selection_toolbar: "removeformat | bold italic underline strikethrough | fontsizeselect forecolor backcolor", plugins: "link image media table lists fullscreen quickbars", language: 'zh_CN', height: 350 } } } } </script>
|
12.ESLint规范
1.相关插件 ESLint和 Prettier



semi: [“warn”,”never”]不加分号,加了给警告

解决单引号警告问题
在eslint.js下添加如下配置
1 2 3 4 5 6
| 'prettier/prettier': [ 'warn', { singleQuote: true } ]
|
加密: