20.Vue实战项目:电商管理系统(Element-UI)
20.Vue实战项目:电商管理系统(Element-UI)
前端技术栈:Vue,Vue-Router,Element-UI,Axios,Echarts 后端技术栈:Node.js,Express,Jwt(模拟session),Mysql,Sequelize(操作数据库的框架)
1.项目初始化登录功能开发
登录业务的相关技术点 :http 是无状态的 ,登录成功后需要记录登录状态
- 通过 cookie和session
- 通过 cookie 在客户端记录状态
- 通过 session 在服务器端记录状态
- 通过 token 方式维持状态
1.1 登录 — token 原理分析

【20】Vue实战项目:电商管理系统(Element-UI)\day01-项目初始化登录功能开发\11.登录功能实现_.mp4
介绍到开发时创建git分支
1.2 登录页面的布局
登录页面的布局 通过 Element-UI 组件实现布局
- el-form
- el-form-item
- el-input
- el-button
- 字体图标

1.3 实现登录
① 通过 axios 调用登录验证接口
② 登录成功之后保持用户 token 信息
③ 跳转到项目主页
submitForm(formName) {
this.$refs.loginFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.post('login', this.loginForm)
if (res.meta.status !== 200) {
this.$message.error('登录失败!')
return
}
this.$message.success('登录成功')
// 1. 将登录成功之后的 token,保存到客户端的 sessionStorage 中
// 1.1 项目中出了登录之外的其他API接口,必须在登录之后才能访问
// 1.2 token 只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage 中
window.sessionStorage.setItem('token', res.data.token)
// 2. 通过编程式导航跳转到后台主页,路由地址是 /home
//this.$router.push('/home')
})
},
1.4 路由导航守卫控制访问权限
如果用户没有登录,但是直接通过URL访问特定页面,需要重新导航到登录页面。
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/home', component: Home }
]
})
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') {
return next();
}
// 获取token
const tokenStr = window.sessionStorage.getItem('token');
if (!tokenStr) {
return next('/login');
}
next();
})
export default router
1.5 退出
logOut () {
// 清空 tocken
window.sessionStorage.clear();
// 重定向到页面
this.$router.push('/login')
}
2. 用户列表功能开发
2.1 通过接口获取菜单数据 通过axios请求拦截器添加token,保证拥有获取数据的权限
// axios请求拦截
axios.interceptors.request.use(config => {
// 为请求头对象,添加 Token 验证的 Authorization 字段
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
2.2 实现首页的路由重定向
home.vue 页面
<!-- 头部 -->
<el-header class="home-header">头部</el-header>
<el-aside>左侧菜单</el-aside>
<!-- 右侧内容主体 -->
<el-main>
<!-- 路由占位符 -->
<router-view></router-view>
</el-main>
登录成功后跳转到home组件,该组件是 首页,定义头部,左侧菜单,右侧内容主体
现在跳转到home组件后,需要右侧重定向到welcome 组件 ,
- 左侧内容主体 先用 路由占位符
<router-view></router-view>- 指定 重定向&子路由 { path: '/home', component: Home,
redirect: '/welcome',children: [.........] },
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login },
{
path: '/home',
component: Home,
redirect: '/welcome',
children: [
{ path: '/welcome', component: Welcome },
{ path: '/users', component: Users }
]
}
]
})
3. 权限管理
项目优化
https://blog.csdn.net/pauline_/article/details/112972570
1. 项目优化策略
- 生成打包报告
- 第三方库启用CDN
- Element-UI 组件按需加载
- 路由懒加载
- 首页内容定制
2. 生成打包报告
打包时,为了直观地发现项目中存在的问题,可以在打包时生成报告。生成报告的方式有两种:
① 通过命令行参数的形式生成报告
## 通过 vue-cli 的命令选项可以生成打包报告
## --report 选项可以生成 report.html 以帮助分析包内容
vue-cli-service build --report
② 通过可视化的UI面板直接查看报告(推荐) 在可视化的UI面板中,通过控制台和分析面板,可以方便地看到项目中所存在的问题。 1
3. 通过 vue.config.js 修改 webpack 的默认配置
通过 vue-cli 3.0 工具生成的项目,默认隐藏了所有 webpack 的配置项,目的是为了屏蔽项目的配置过程,让程 序员把工作的重心,放到具体功能和业务逻辑的实现上。 如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从 而对项目的打包发布过程做自定义的配置(具体配置参考 https://cli.vuejs.org/zh/config/#vue-config-js)。
4. 为开发模式与发布模式指定不同的打包入口
默认情况下,Vue项目的开发模式与发布模式,共用同一个打包的入口文件(即 src/main.js)。为了将项目 的开发过程与发布过程分离,我们可以为两种模式,各自指定打包的入口文件,即:
① 开发模式的入口文件为 src/main-dev.js
② 发布模式的入口文件为 src/main-prod.js
5. configureWebpack 和 chainWebpack
在 vue.config.js 导出的配置对象中,新增 configureWebpack 或 chainWebpack 节点,来自定义 webpack 的打包配置。 在这里, configureWebpack 和 chainWebpack 的作用相同,唯一的区别就是它们修改 webpack 配置的方 式不同:
① chainWebpack 通过链式编程的形式,来修改默认的 webpack 配置
② configureWebpack 通过操作对象的形式,来修改默认的 webpack 配置
两者具体的使用差异,可参考如下网址: https://cli.vuejs.org/zh/guide/webpack.html#webpack-相关
6. 通过 chainWebpack 自定义打包入口
module.exports = {
chainWebpack: config => {
config.when(process.env.NODE_ENV === 'production', config => {
config.entry('app').clear().add('./src/main-prod.js')
})
config.when(process.env.NODE_ENV === 'development', config => {
config.entry('app').clear().add('./src/main-dev.js')
})
}
}
7. 通过 externals 加载外部 CDN 资源
默认情况下,通过 import 语法导入的第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包成功 后,单文件体积过大的问题。 为了解决上述问题,可以通过 webpack 的 externals 节点,来配置并加载外部的 CDN 资源。凡是声明在 externals 中的第三方依赖包,都不会被打包。
vue.config.js
module.exports = {
chainWebpack: config => {
config.set('externals', {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
lodash: '_',
echarts: 'echarts',
nprogress: 'NProgress',
'vue-quill-editor': 'VueQuillEditor'
})
}
}
说明:主要是对下面的几个插件进行优化
import './plugins/element.js'
// require styles 导入富文本编辑器对应的样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
同时,需要在 public/index.html 文件的头部,添加如下的 CDN 资源引用:
<!-- nprogress 的样式表文件 -->
<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" />
<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>
<!-- 富文本编辑器的 js 文件 -->
<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>
8. 通过 CDN 优化 ElementUI 的打包
虽然在开发阶段,我们启用了 element-ui 组件的按需加载,尽可能的减少了打包的体积,但是那些被按需加 载的组件,还是占用了较大的文件体积。此时,我们可以将 element-ui 中的组件,也通过 CDN 的形式来加 载,这样能够进一步减小打包后的文件体积。 具体操作流程如下:
① 在 main-prod.js 中,注释掉 element-ui 按需加载的代码
② 在 index.html 的头部区域中,通过 CDN 加载 element-ui 的 js 和 css 样式
<!-- element-ui 的样式表文件 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />
<!-- element-ui 的 js 文件 -->
<script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>
9. 首页内容定制
不同的打包环境下,首页内容可能会有所不同。我们可以通过插件的方式进行定制,插件配置如下:
chainWebpack: config => {
config.when(process.env.NODE_ENV === 'production', config => {
config.plugin('html').tap(args => {
args[0].isProd = true
return args
})
})
config.when(process.env.NODE_ENV === 'development', config => {
config.plugin('html').tap(args => {
args[0].isProd = false
return args
})
})
}
在 public/index.html 首页中,可以根据 isProd 的值,来决定如何渲染页面结构:
<!– 按需渲染页面的标题 -->
<title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>
<!– 按需加载外部的 CDN 资源 -->
<% if(htmlWebpackPlugin.options.isProd) { %>
<!—通过 externals 加载的外部 CDN 资源-->
<% } %>
10. 路由懒加载
对于SPA单页应用,当打包构建时,JavaScript包会变得非常大,影响页面加载速度,将不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这就是路由的懒加载。 具体需要 3 步:
① 安装 @babel/plugin-syntax-dynamic-import 包。
② 在 babel.config.js 配置文件中声明该插件。
③ 将路由改为按需加载的形式,示例代码如下:
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-boo" */ './Baz.vue')
注: 组件分组,例如上面 通过 webpackChunkName 指定分组名称,将 Foo 和Bar 分到 group-foo 组,在编译时, Foo 和Bar 生成一个js 文件,当访问其中一个时,才会加载该js 文件
关于路由懒加载的详细文档,可参考如下链接: https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
上线
https://blog.csdn.net/qq_37970097/article/details/109693863
https://blog.csdn.net/weixin_40496794/article/details/122979654
1. 项目上线相关配置
1.通过 node 创建 web 服务器。
2.开启 gzip 配置。
3.配置 https 服务。
4.使用 pm2 管理应用。
2. 通过 node 创建 web 服务器
创建 node 项目,并安装 express,通过 express 快速创建 web 服务器,将 vue 打包生成的 dist 文件夹, 托管为静态资源即可
具体实现:
2.1 初始化npm
新建文件夹,然后命令行执行 npm init
运行完之后会出现一个package.json的配置文件,说明初始化npm成功
2.2 安装express
执行 npm i express
2.3 创建app.js 文件
const express = require('express')
// 创建 web 服务器
const app = express()
// 托管静态资源
app.use(express.static('./dist'))
// 启动 web 服务器
app.listen(80, () => {
console.log('web server running at http://127.0.0.1')
})
编写一个简单的 get/post 接口
// 1.引入框架
// node项目采用 common.js,不能采用 import 引入,只能用 require 方式
const { response } = require('express')
const express = require('express')
// 2.创建应用
const app = express()
// 3.创建路由规则
// get请求
app.get('/hello', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置响应体
response.send('Hello node')
})
// post请求
app.post('/server', (request, response) => {
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*')
// 设置所有相应头可用
response.setHeader('Access-Control-Allow-Headers', '*')
let query = request.query
// 设置响应体,返回请求参数
response.status(200).send(query)
})
// 4.监听端口启动服务
app.listen(8280, () => {
console.log('服务已经启动,8280端口监听中...,点击http://localhost:8280');
})
2.4 启动 node app
3. 开启 gzip 配置
使用 gzip 可以减小文件体积,使传输速度更快。 可以通过服务器端使用 Express 做 gzip 压缩。其配置如下:
// 安装相应包
npm install compression -S
// 导入包
const compression = require('compression');
// 启用中间件
app.use(compression());
完整
const express = require('express')
const compression = require('compression')
const app = express()
// 一定要把这一行代码,写到 静态资源托管之前
app.use(compression())
app.use(express.static('./dist'))
app.listen(80, () => {
console.log('server running at http://127.0.0.1')
})
4. 配置 HTTPS 服务
为什么要启用 HTTPS 服务?
传统的 HTTP 协议传输的数据都是明文,不安全
采用 HTTPS 协议对传输的数据进行了加密处理,可以防止数据被中间人窃取,使用更安全
申请 SSL 证书(https://freessl.org)个人免费
① 进入 https://freessl.cn/ 官网,输入要申请的域名并选择品牌。
② 输入自己的邮箱并选择相关选项。
③ 验证 DNS(在域名管理后台添加 TXT 记录)。
④ 验证通过之后,下载 SSL 证书( full_chain.pem 公钥;private.key 私钥)。
在后台项目中导入证书
const https = require('https');
const fs = require('fs');
const options = {
cert: fs.readFileSync('./full_chain.pem'),
key: fs.readFileSync('./private.key')
}
https.createServer(options, app).listen(443);
5. 使用 pm2 管理应用
① 在服务器中安装 pm2:npm i pm2 -g
② 启动项目:pm2 start 脚本 --name 自定义名称
③ 查看运行项目:pm2 ls
④ 重启项目:pm2 restart 自定义名称
⑤ 停止项目:pm2 stop 自定义名称
⑥ 删除项目:pm2 delete 自定义名称