# vue-shop
**Repository Path**: baiyeyue/vue-shop
## Basic Information
- **Project Name**: vue-shop
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-09-22
- **Last Updated**: 2021-04-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Vue全家桶-项目实战 vue-shop
# 1. 电商后台管理系统的功能
## 1.1. 电商后台管理系统的功能有:用户管理、权限管理、商品管理、订单管理、数据统计等业务功能
## 1.2. 电商后台管理系统的开发模式(前后端分离)
```
电商后台管理系统整体采用前后端分离的开发模式,其中前端项目是基于 Vue 技术栈的 SPA 项目。
```
## 1.3. 电商后台管理系统的技术选型-前端技术栈
- Vue
- Vue-router
- Element-UI
- Axios
- Echarts
# 2. 项目初始化
## 2.1. 前端项目初始化步骤
1. 安装Vue脚手架
2. 通过Vue脚手架创建项目
3. 配置Vue-router路由
4. 配置Element-UI组件库
5. 配置Axios库
6. 初始化git远程仓库
7. 将本地项目托管到git或码云仓库中
## 2.2.登录功能
### 2.2.1.登录概述
#### 2.2.1.1.登录业务流程
* 用户输入用户名密码登录
* 调用后台接口进行验证
* 通过验证之后根据后台响应状态跳转到相关页面
#### 2.2.1.2.登录业务的技术点
* http是无状态的
* 通过sessionStorage在客户端记录登录状态
* 通过token方式维持登录状态
### 2.2.2.登录-token原理分析
1. 客户端 用户输入用户名密码进行登录
2. 客户端校验通过后向服务器发送登录请求
3. 服务器 验证通过后生成该用户的token并返回给客户端
4. 客户端存储该token
5. 后续所有的请求都携带token发送请求
### 2.2.3.登录功能的实现
#### 2.2.3.1.登录页面的布局
* 通过Element-UI组件实现布局
```
登录
重置
```
#### 2.2.3.2.实现登录功能
1. 通过axios调用登录验证接口
2. 登录成功之后保存用户token信息
3. 跳转到项目主页
```login() {
this.$refs.loginFormRef.validate(async valid => {
if (!valid) return
const { data: res } = await this.$http.post('login', this.loginForm)
if (res.meta.status !== 200) return this.$message.error('登录失败!')
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')
})
}
```
#### 2.2.3.3.路由导航守卫控制访问权限
* 如果用户没有登录,但是直接通过URL访问特定页面,需要重新导航到登录页面。
``` // 挂载路由导航守卫
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()
})
```
#### 2.2.3.4.Vue直接操作DOM
* 通过ref标注DOM元素
```// 在 DOM 元素上通过 ref 属性标注,属性名称自定义
hello
```
* 通过 $refs 获取 DOM 元素
``` // 通过 Vue 实例的 $refs 获取标记 ref 属性的元素
let info = this.$refs.info.innerHTML
console.log(info) // hello
```
#### 2.2.3.5.基于 Element-UI 进行表单验证
* Element-UI表单验证规则 :
``` loginFormRules: {
/* 表单验证规则 */
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 15, message: '长度在 6 到 15 个字符', trigger: 'blur' }
]
}
```
```// 进行表单验证
this.$refs.loginFormRef.validate(async valid => {
// 如果验证失败,直接退出后续代码的执行
if (!valid) return
// 验证通过后这里完成登录成功后的相关操作(保存token、跳转到主页) })
```
#### 2.2.3.6.axios请求头token配置
```
/* 配置请求根路径 */
axios.defaults.baseURL = 'url'
/* 在request拦截其中,展示进度条 NPropress.start() */
axios.interceptors.request.use(config => {
console.log(config)
NPropress.start()
/* 为请求头对象添加Token验证的Authorization字段 */
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
```
## 2.3.退出登录
* 基于 token 的方式实现退出比较简单,只需要销毁本地的 token 即可。这样,后续的请求就不会携带 token ,必须重新登录生成一个新的 token 之后才可以访问页面。
``` // 清空token
window.sessionStorage.clear()
// 跳转到登录页
this.$router.push('/login')
```
# 3.基础知识点整理
## 3.1. el-cascader实现 省市区/县选择-级联选择器
- 在实现订单修改地址的时候用到
```html
```
```js
//data数据
cascaderProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children'
},
/* 选中的父级分类的id */
selectedKeys: []
parentCateChanged() {
console.log(this.selectedKeys)
/* 如果 selectedKeys 的length大于0 证明选中的父级分类 */
/* 反之 没有选中任何父级分类 */
if (this.selectedKeys.length > 0) {
/* 父级分类的id */
this.selectedKeys.cat_pid = this.selectedKeys[
this.selectedKeys.length - 1
]
/* 为当前分类的等级赋值 */
this.addCateForm.cat_level = this.selectedKeys.length
return true
} else {
/* 父级分类的Id */
this.addCateForm.cat_pid = 0
/* 为当前分类的等级赋值 */
this.addCateForm.cat_level = 0
}
},
```
## 3.2. el-pagination的分页功能
* 项目里所有涉及列表功能都会有分页功能
```html
```
```js
//data变量
queryInfo: {
query: '',
pagenum: 1 /* 当前页数 */,
pagesize: 5 /* 当前每页显示多少条数据 */
}
//js方法
handleSizeChange(newSize) {
console.log(`每页 ${newSize} 条`)
this.queryInfo.pagesize = newSize
this.getUserList()
},
handleCurrentChange(newPage) {
console.log(`当前页: ${newPage}`)
this.queryInfo.pagenum = newPage
this.getUserList()
},
```
## 3.3. 树形结构列表 https://www.npmjs.com/package/tree-table
* 在商品分类列表页有用到
```
npm install tree-table --save
//挂载
Vue.component('tree-table', TreeTable)
```
```html
一级
二级
三级
编辑
删除
```
## 3.4. 时间格式化
```html
{{ scope.row.create_time | dateFormate }}
```
```main.js
Vue.filter('dateFormate', function(originVal) {
const dt = new Date(originVal)
const y = dt.getFullYear()
const m = (dt.getMonth() + 1 + '').padStart(2, '0')
const d = (dt.getDate() + '').padStart(2, '0')
const hh = (dt.getHours() + '').padStart(2, '0')
const mm = (dt.getMinutes() + '').padStart(2, '0')
const ss = (dt.getSeconds() + '').padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})
//放在main.js里
```
# 4.电商管理系统(Element-UI)打包阶段项目优化
## 4.1.添加loading进度条效果
1. 添加loading进度条效果 https://github.com/rstacruz/nprogress
```
npm install --save nprogress
```
2. 在main.js中导入 NPropress
```
/* 导入 nprogress 包对应的js和css */
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
```
3. 在请求拦截器中调用NProgress.start()展示进度条
```
/* 在request拦截其中,展示进度条 NPropress.start() */
axios.interceptors.request.use(config => {
console.log(config)
NProgress.start() //显示进度条
/* 为请求头对象添加Token验证的Authorization字段 */
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
/* 在response拦截器中,隐藏进度条 NPropress.done() */
axios.interceptors.response.use(config => {
NProgress.done() //隐藏进度条
return config
})
```
## 4.2.**使用 babel-plugin-transform-remove-console 清楚项目中的console**
## 5.3.加载外部CDN
* vue.config.js自定义webpack配置、通过externals加载外部CDN
1. 通过chainWebpack自定义打包入口
```
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': 'router',
axios: 'axios',
loadsh: '_',
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
})
})
}
}
```
2. HTML中做判断
```html
<%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统
<% if(htmlWebpackPlugin.options.isProd){ %>
<% } %>
```
3. 路由懒加载
https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
```
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
```
4. **baberl.config.js 里配置 @babel/plugin-syntax-dynamic-import**
```
//这是项目发布阶段需要用到的babel插件
const prodPlugins = []
if (process.env.NODE_ENV === 'production') {
prodPlugins.push('transform-remove-console')
}
module.exports = {
presets: [
'@vue/app'
],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
],
//发布产品时候的插件数组
...prodPlugins,
//路由懒加载
'@babel/plugin-syntax-dynamic-import'
]
}
```
# 5.项目上线相关配置
## 5.1. 通过node创建web服务
通过node创建web服务
``` npm init -y
npm init -y
npm i express -S
```
创建node项目,并安装express,通过express快速创建web服务器,将vue打包生成的dist文件夹,托管为静态资源即可,关键代码如下:
``` const express = require('express')
const express = require('express')
//创建web服务器
const app = express()
//托管静态资源
app.use(express.static('./dist'))
//启动web服务器
app.listen(80, () => {
console.log('server running at http://127.0.0.1')
})
//启动服务
node ./app.js
```
## 项目初始化
```
yarn install
```
### 本地运行
```
yarn serve
```
### 打包发布
```
yarn build
```
# 写的比较长,谢谢耐心观看!