# 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 ``` ```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 ``` # 写的比较长,谢谢耐心观看!