# vue-ShopProject **Repository Path**: yayuyang/vue-ShopProject ## Basic Information - **Project Name**: vue-ShopProject - **Description**: 后台管理项目的优化练习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-09 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 电商后台管理系统(前端项目) [后端源码]: https://gitee.com/yayuyang/vue_-shop-project_server ​ 接口API [前端源码]: https://gitee.com/yayuyang/vue-ShopProject ### 运行步骤: 1 下载后端源码并运行起来 ``` npm install node ./app.js ``` 2 安装phpStudy并导入**mydb** 3 使用postman测试api接口(可选) 4 下载前端源码 > npm install > > 执行vue ui命令**打开ui界面**,然后**任务 --> 运行server --> 编译成功**,**运行app**查看当前项目效果 ### 功能 > 用于管理用户账号,商品分类,商品信息,订单,数据统计等业务功能 ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908230141050.png) ### 开发模式 > 电商后台管理系统整体采用前后端分离的开发模式,其中前端项目是基于Vue技术栈的SPA项目 > > SPA(single page application,单页面应用),整个网站只有一个页面,内容变化通过Ajax局部更新实现,同时支持浏览器地址栏的前进和后退操作 > > > > **基本思路:** > > 1. 先将需要用到的组件(统一放在components文件夹)写好。 > > ​ 为了快速开发,可按需导入第三方插件(plugins/elements.js),减少打包后的项目体积 > > 2. 给写好的组件合成一个路由(规划路线)(router/index.js)。 > > 3. 将合成好的路由放到根组件中(路由占位符)。 > > 4. 将路由器挂载在vue的实例上(main.js)。 > > 5. 定义瞄点 (body) > > 6. 尝试跳转 (body) ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/mall_desc02.png) ### 技术选型 #### 前端项目技术栈 - Vue - Vue-router - Element-UI - Axios - Echarts #### 后端项目技术栈 - Node.js - Express - Jwt - Mysql - Sequelize ### 0 项目初始化 #### 前端项目初始化步骤 1. 安装 Vue 脚手架 2. 通过 脚手架创建项目 3. 配置 Vue-router 4. 配置 Element-UI 组件库 5. 配置 Axios 库 6. 初始化 git 远程仓库 7. 将本地项目托管到github或者码云中 ##### 相关依赖-按需导入 ![]( https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/mall_desc03.png) #### 后端项目的环境安装配置 1. 安装MySQL数据库,简易安装phpStudy并导入**mysql**数据库数据 2. 安装Node.js环境,node -v,npm -v 检查安装是否成功 3. 配置后台项目,从终端打开后台项目vue_api_server,运行其中的app.js文件(开发中使用) 4. 使用Postman测试后台项目接口是否正常(开发中使用) ### 补充:处理ESLint警告 默认情况下,ESLint和vscode格式化工具有冲突,需要添加配置文件解决冲突。 在项目根目录添加 .prettierrc 文件 ### 1 登录概述 #### 1.1 登录业务流程 1. 在登录页面输入账号和密码进行登录,将数据发送给服务器 2. 服务器返回登录的结果,登录成功则返回数据中带有token 3. 客户端得到token并进行保存,后续的请求都需要将此token发送给服务器,服务器会验证token以保证用户身份。 #### 1.2 登录状态保存逻辑 1. http是无状态的 2. 如果服务器和客户端同源,建议可以使用**cookie或者session**来保持登录状态 3. 如果客户端和服务器跨域了,建议使用**token**进行维持登录状态。token是SC之间身份校验 #### 1.3 登录页面的布局 1. main.js文件中 挂载路由,将根组件渲染到页面内 2. 梳理出最简单的模板, 3. 添加表单组件、第三方字体、表单验证、axios 、配置弹窗提示 1. 创建组件,布局(头部和表单) 2. 表单数据绑定、表单数据验证、重置、发起请求、弹窗提示、成功后的行为(保存 token、导航至/home)、路由导航守卫控制 #### 补充:路由导航守卫控制访问权限 > 如果用户没有登录,但是直接通过URL访问特定页面,需要重新导航到登录页面 > > 为路由模块添加beforeEach导航守卫 ### 2 主页概述 #### 2.1 获取数据的权限 > 后台除了登录接口之外,都需要token权限验证,我们可以通过添加axios请求拦截器来添加token,以保证拥有获取数据的权限 > > 在入口文件中(main.js)通过axios请求拦截器添加token,保证拥有获取数据的权限 > #### 2.1主页页面的布局 1. 基本布局:整体为一个container,包含了header和子级container(侧边栏、主体) 2. 侧边栏布局,先导入插件 Menu, Submenu, MenuItem, 3. 添加axios请求拦截器来添加token,以保证拥有获取数据的权限 4. 在created阶段请求左侧菜单数据,通过v-for双重循环渲染左侧菜单 5. 设置激活子菜单样式(el-menu的active-text-color属性),还使用第三方字体图标,还有el-menu中添加一个属性unique-opened,每次只能打开一个子菜单 6. 制作侧边菜单栏的伸缩功能 7. **添加子级路由**(***) 在router.js中导入组件并设置**路由规则**以及子级路由的**默认重定向**/welcome,主体结构中添加一个**路由占位符**,侧边栏二级菜单都改造成子级路由链接,根据菜单的path属性进行路由跳转 8. 当点击二级菜单的时候,被点击的二级子菜单要设置为高亮 将path保存到sessionStorage中,将el-menu的default-active属性设置为activeIndex,最后在created中将sessionStorage中的数据赋值给activeIndex ### 3 用户列表 #### 3.1 基本结构 1. 面包屑组件完成顶部导航路径 2. 卡片组件完成主体表格 3. 输入框组件完成搜索框及搜索按钮 4. 栅格布局来划分结构,使用el-button制作添加用户按钮 #### 3.2 请求数据并分页展示数据 **表格组件**完成列表展示数据,在渲染状态、操作列,使用作用域插槽来进行,还有**文字提示组件、switch开关组件、分页组件** #### 3.3 子功能实现 状态切换、删除、修改、搜索、添加用户 ### 4 权限管理 #### 权限管理业务分析 > 通过权限管理模块可以为用户设置角色,角色包括不同的功能权限 > > - 编辑角色名称、角色描述、 > - 删除该角色 > - 为该角色分配权限,完成树形结构弹窗 > - 点击左边的三角可以查看该角色的具体权限,使用三重嵌套for循环生成权限下拉列表,美化样式,添加权限删除功能 > - 再回头打开Users.vue,完成分配角色的功能 ![]( https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/mall_desc05.png) ### 5 商品管理goods #### 5.1 商品列表list概述 > 具有展示商品信息,搜索是商品和添加商品的功能 > > #### 5.2 分类参数paras概述 > 商品参数用于描述商品的特征信息,可以通过电商平台详情页面直观的看到 > > 添加子级路由,创建组件完成基本布局 > > 警告提示信息使用了el-alert,级联选择框,添加静态/动态参数、编辑、修改、删除、展示参数 #### 5.3 商品分类cate概述 > 商品分类用于在购物时,快速找到需要购买的商品,进行直观显示 > > 使用第三方插件vue-table-with-tree-grid展示分类数据, > > 使用Cascader组件实现级联菜单显示父级分类 ### 6 订单管理 #### 6.1 订单列表概述 > ### 7 数据统计 #### 7.1 数据报表概述 > ### 小结:项目所用依赖 1. 运行依赖 - axios => 发送请求 - echarts => 图表 - element-ui => element ui组件 - moment => 时间处理工具库 - nprogress => 进度条库 - v-viewer => 图片预览工具库 - vue-quill-editor => 富文本编辑器 - vue-table-with-tree-grid => 树形菜单/表格 2. 开发依赖 - babel => es6+语法转换 - eslint/babel-eslint => 语法检查 - less/less-loader => less语法 - babel-plugin-transform-remove-console => 移除console插件 ### 8项目优化 > A.生成打包报告,根据报告优化项目 > B.第三方库启用CDN > C.Element-UI组件按需加载 > D.路由懒加载 > E.首页内容定制 #### 8.1 项目优化策略 ##### 8.1.1 生成打包报告 - 通过命令行参数形式生成报告=>vue-cli-service build --report - **推荐:**通过可视化ui面板直接查看报告(通过控制台和分析面板) - 通过vue.config.js修改webpack的默认配置 > 通过vue-cli 3.0工具生成的项目,默认隐藏了所有webpack的配置项,目的是为了屏蔽项目的配置过程,让开发人员把工作的重心,放在具体功能和业务逻辑的实现上 > > 如果我们需要修改配置webpack,则通过新建文件vue.config.js来配置。 - 为开发模式与发布模式指定不同的打包入口 > 默认情况下,vue项目的开发与发布模式,共用同一个打包的入口文件(即src/main.js),为了将项目的开发过程与发布过程分离,可以为两种模式,各自指定打包的入口文件,即: > > 1. 开发模式入口文件 src/main-dev.js > 2. 发布模式入口文件 src/main-prod.js > > 方案:configureWebpack(通过链式编程形式)和chainWebpack(通过操作对象形式) > > 在vue.config.js导出的配置文件中,新增configureWebpack或chainWebpack节点,来自定义webpack的打包配置 ```js // 代码示例 module.exports = { chainWebpack: config => { // 发布模式 config.when(process.env.NODE_ENV === 'production', config => { //entry找到默认的打包入口,调用clear则是删除默认的打包入口 //add添加新的打包入口 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') }) } } ``` ##### 8.1.2 第三方库启用CDN - 通过externals加载外部cdn资源 > 默认情况下,通过import语法导入的第三方依赖包,最终会打包合并到同一个文件中,从而导致打包成功后,单文件体积过大的问题 => **chunk-vendors**体积过大 > > 为了解决上述问题,可以通过webpack的externals节点,来配置加载外部的cdn资源,凡是声明在externals中的第三方依赖包,都不会被打包 > > 原理:在打包期间,webpack先检查externals中有没有声明依赖包,如果有将不会打包进chunk-vendors,在用到这些依赖包的时候,会在全局对象Window找到现成的来使用 1. 步骤1 在vue.config.js如下配置 ```js module.exports = { chainWebpack: config => { config.when(process.env.NODE_ENV === 'production', config => { config.entry('app').clear().add('./src/main-prod.js') // 在vue.config.js如下配置 config.set('externals', { vue: 'Vue', 'vue-router': 'VueRouter', axios: 'axios', lodash: '_', echarts: 'echarts', nporgress: 'NProgress', 'vue-quill-editor': 'VueQuillEditor' }) }) config.when(process.env.NODE_ENV === 'development', config => { config.entry('app').clear().add('./src/main-dev.js') }) } } ``` 2. 步骤2 > 在public/index.html文件头部,将main-prod中的已经进行配置的import(样式表)富文本和进度条删除,替换为cdn引入 ```css ``` 3. 步骤3 > 在public/index.html文件头部,将main-prod中的已经进行配置的import(js文件)删除,替换为cdn引入 > > 为了保证在全局对象中包含这些依赖包,在index.js头部文件中加入这些的引用 ```css ``` 4. cdn加速前后对比( **chunk-vendors**打包文件) > Parsed大小 2.6m=> **596.9kB** - 使用cdn优化elementui打包 ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/image-20200710202019765.png) > 具体操作流程 > > 1. 在main-prod.js中,注释掉element-ui按需加载的代码import './plugins/elements.js' > 2. 在index.html头部区域中,通过cdn加载element-ui的js和css样式 > > `` > > `` ##### 8.1.3 首页内容定制 > 不同打包环境下,首页内容可能会有所不同,通过插件方式定制 - vue.config.js配置 ```js // 配置。HTML插件。tap函数(修改插件中的相关参数--增加变量args为该插件中的参数项) config.plugin('html').tap(args => { args[0].isProd = true或false // true 表示为产品模式 return args }) ``` - index.html修改 ```html <%= htmlWebpackPlugin.options.isProd ? '' : 'dev-' %>vue-mall <% if(htmlWebpackPlugin.options.isProd) { %> css | js放在这儿 <% } %> ``` ##### 8.1.4 路由懒加载 > 在打包构建项目时,javascript包会变得特别大,影响页面加载,如果我们能把不同路由对应的组件分隔成不同的代码块,然后当路由被访问的时候才加载对应组件,这样更加高效 - 安装@babel/plugin-syntax-dynamic-import包,才支持下面import中语法import(/* 分组组名 */ ' 组件位置 ') - 在babel.config.js配置文件声明该插件 - 将路由改为按需加载形式 ```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') // import Login from '../components/Login.vue' const Login = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Login.vue') // import Home from '../components/Home.vue' const Home = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Home.vue') // import Welcome from '../components/Welcome.vue' const Welcome = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Welcome.vue') ... ``` 具体内容参考文章底部链接 ### 9 项目上线 #### 9.1 通过node创建web服务器 > 新创建文件夹vueshop-server,并安装express,通过express快速创建web服务器,将vue打包生成的dist文件夹,托管为静态资源即可,关键代码如下 ```js // 新创建文件夹vueshop-server, // 1. npm init -y // 2. npm i express -S // 3. 将打包后的dist放入文件夹中 const express = require('express') // 创建web服务器 const app = express() // 托管静态资源,注册一个中间件,将制定目录托管为静态资源 app.use(express.static('./dist')) // 启动web服务器 app.listen(80, () => { console.log('server runing at http://127.0.0.1') }) // 5. node app.js启动项目 // 6. http://127.0.0.1浏览器打开该网址 ``` #### 9.2 开启gzip配置 > 通过gzip减小文件体积,使传输速度更快 ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/image-20200710205845756.png) 使用gzip后(上面为传输体积,下面为实际体积) ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/image-20200710210112657.png) ##### 9.2.1 在服务器端使用express做gzip压缩,配置如下 ```js // 1.npm install compression -S // 2.导入包 const compression = require('compression') // 3.启用中间件,写在静态资源托管代码之前,先压缩再托管 app.use(compression()) ``` #### 9.3 配置https服务 ##### 9.3.1 为什么要启用https服务 - 传统的http协议传输的数据都是明文,不安全 - 采用https协议对传输的数据进行了加密处理,可以防止数据被中间人窃取,使用更安全 申请ssl证书(https://freessl.org) => 正常企业还是使用收费ssh(http协议默认运行在80端口,https默认运行在443端口) ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/image-20200710210440240.png) #### 9.4 使用pm2管理应用 ```js 1. npm i pm2 -g //全局安装 2. pm2 start 脚本(如./app.js) --name 自定义名称 // 启动项目 3. pm2 ls //查看服务器运行的项目 4. pm2 restart 自定义名称 //重启项目 5. pm2 stop 自定义名称 //停止项目 6. pm2 delete 自定义名称 //删除项目 ``` ![](https://gitee.com/yayuyang/vue-shop-admin/raw/master/image/mall_desc06.png) ### 10 部份页面预览 ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223043361.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223208469.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223238747.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223914970.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223754737.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908223822772.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908224022751.png) ![](https://gitee.com/yayuyang/vue-ShopProject/raw/master/readme-images/image-20200908224107597.png)