基于Element-ui和vue的电商管理项目+建立码云仓库+git
1. 项目概述
1.1 电商后台管理系统的开发模式(前后端分离)
前端:制作页面,利用ajax调用后端api接口
前后端分离开发模式:后端写接口,前端调接口
前端技术栈
-
vue
-
vue-router
-
Element-UI 前端UI组件库
-
Axios 发起网络数据请求
-
Echarts 绘制报表
后端技术栈
-
Node.js
-
Express
-
Jwt 状态保持工具 模拟登陆记录功能
-
Mysql
-
Sequelize 操作数据库的框架
2. 项目初始化
2.1 前端项目初始化步骤
-
安装Vue脚手架
-
通过脚手架构建项目
-
vue ui 可视化创建vue项目
-
项目手动配置:手动配置 -Linter(语法格式校验保证代码风格一致)使用配置文件 babal
-
配置Vue路由
-
配置Element-UI组件库 可视化添加插件
-
配置axios库 可视化添加依赖 运行依赖
2.2 后台项目的环境安装配置
-
安装Mysql
在Navicat中导入mydb.sql 命名为vue_shop_yfh
-
安装Node.js环境
-
配置项目相关信息
-
启动项目
-
使用postman测试后台项目接口是否正常
-
vue_api_server 中装有项目的依赖包,
-
shift 右键打开PowerShell,其中npm install安装 cls清空
-
在power shell 中 node .\app.js 启动后端服务
-
postman 中传递参数在body→x-www.form-urlencoded(普通表单数据格式 → 后端与数据库连接成功
配置数据库信息
-
token 用来登录状态保存 (相当于node中的session,客户端与服务区之间的状态保存机制)
3 登录/退出功能
3.1 登录概述
-
登录业务流程
-
在登录页面输入用户名和密码
-
调用后台接口进行验证
-
通过验证之后,根据后台的响应状态跳转到项目主页
-
-
登录业务的相关技术点
-
http是无状态的
-
通过cookie在客户端记录状态(node)、通过session在服务端记录状态(node)
-
通过token方式维持状态
-
此vue项目运行在一个新的端口号,服务器可能与前端vue项目之间有跨域问题(协议 域名 端口号有不一致)
如果前端与后台接口之间不存在跨域问题,推荐cookie和session来记录登录状态
如果前端与后端存在跨域问题,则用token维持登录状态
3.2 登录-token原理分析
token完成客户端与服务器端身份验证(身份令牌)
3.3 登录功能实现
1 登录页面的布局
-
el-form
-
el-form-item(3个)
-
el-input
-
el-button
-
字体图标
2 梳理项目结构
查看项目运行效果→ 打开vue ui →任务→运行启动app
项目代码 →src →main.js(项目入口文件)
App.vue 项目根组件
3 渲染Login组件并实现路由重定向
comp onents新建 →router/index.js 中导入,定义路由规则→在App.vue中放路由占位符<router-view>
通过路由匹配的组件都会渲染到router-view中
路由定义时候 因为eslint影响,常报错
{ path: '/login', component: Login } //括号里前后各有空格,冒号后有空格
<style lang="less" scoped> //支持less 语法格式 scoped为vue指令控制组件样式生效的区间,加上scope样式只在当前组件生效,否则回全局生效(样式冲突)
创建登陆组件,通过路由的形式将登录组件渲染到App根组件中,通过路由重定向redirect让用户在访问/根页面时候自动跳转到登录页面
4 设置背景色并在屏幕中央绘制登陆盒子
可视化安装开发依赖:less-loader\less
-
让背景色充满页面→在页面中检查元素 看哪些标签需要撑满屏幕→定义全局样式表html\body\#app→在入口文件中导入全局样式
为登录组件设置背景颜色,在登陆组件中放入一个盒子,设置好宽高,背景色,盒子放正中央
5 绘制默认头像
6 绘制登录表单区域
-
需要element-ui哪些组件 →plugins/element.js中按需导入→Vue.use()注册为全局可用的组件
7 绘制带icon的input输入框
-
input输入框找icon怎么写:添加prefix-icon属性(前置小图标)(suffix-icon后置小图标)
-
element-ui/第三方图标库阿里图标库
-
步骤:
-
将fonts复制到assets中
-
一:导入图表样式表:到入口文件main.js中导入字体图标
-
二:对应组件中添加iconfont基础类+具体使用图标名
import './assets/fonts/iconfont.css' // 导入字体图标
import './assets/css/global.css' // 导入全局样式表 -
<el-input prefix-icon="iconfont icon-user"></el-input>
// 到demo_fontclass找用法
-
8 实现表单的数据绑定
-
v-model数据绑定
★ ①el-form用:model 属性进行数据绑定,值是一个数据对象(在data中做定义)
②子组件el-form-item用v-model(绑定到数据对象上具体的属性中),否则显示不了
-
设置密码框 type="password" 隐藏密码
9 表单数据验证
在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误
-
为el-form属性绑定 ,添加 :rules='rules' 绑定验证规则对象
-
在data中定义校验对象rules,其中每个属性就是验证规则
-
为el-form-item通过prop指定不同验证规则进行表单验证
-
trigger: 'blur/change' 鼠标失去焦点,触发此次验证
-
10 表单重置
拿到表单实例对象(给el-form添加 ref 引用)调用resetFields函数
-
给表单添加ref引用对象
-
methods:添加重置表单方法,通过this 访问$refs.loginFormRef ,调用resetFields()
this.$refs.loginFormRef.resetFields()
11 登陆前表单数据的预验证
获取表单的引用对象,调用validate函数,在validate中接收回调函数,其中第一个形参是验证的结果为布尔值
如果箭头函数只有一个形参,可以省略()
this.$refs.loginFormRef.validate(valid => { // validate((valid) => {
console.log(valid)
})
valid(xx,xx)=>{}
12 配置axios发起登录请求(根据验证的结果是否发起具体的请求)
-
到main.js对axios进行全局配置:
-
先导入,接着将axios包挂载到原型对象上。如此每一个vue组件都可以通过this直接访问到$http,从而去发起axios请求。
-
为axios设置请求的根路径
Vue.prototype.$http = axios
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/' -
-
运行mysql .powershell中运行node .\app.js(vue_api_server在这个文件夹里!)
-
如果某个方法的返回值是promise,可以用await简化promise操作
-
注意:await只能用在被修饰的async方法中,所以接下来应将紧挨着await的那个方法修饰成异步的async方法
-
-
这返回的六个属性都是axios封装好的,只有data才是服务器返回的真实数据,所以从result中将data解构赋值出来,将data重命名为res,从而打印真实的服务器数据
const { data: res } = await this.$http.post('login', this.loginForm)
-
-
账号admin/123456 是已经存在的
先判断valid是否为true,为true则直接发起请求,如果不等于true直接return.验证通过了去配置axios,挂载到原型对象上设置请求根路径,如此在组件中就可以直接用this来发起登录请求。post返回值是promise,为了简化这次promise操作,可用async.await来优化,await只能用在被async修饰的方法中,所以将await外面的箭头函数修饰成异步的函数,如此就可直接拿到服务器返回的数据。返回6个属性,拿到data服务器返回数据,从result数据对象中解构复制出data属性并重命名为res对象,根据res的meta属性打印
13 配置message全局弹框组件
-
在element.js中导入弹框提示组件,message的配置方式和其他不一样,需要全局挂载,挂载为vue原型上的一个属性,起名为message
Vue.prototype.$message = Message
$message是自定义属性,可任意改名。
将弹框组件挂载到vue的原型组件上,如此每一个组件都可通过this访问$message,进行弹框提示,有success,error函数...
14 完善登录成功之后操作
-
将登陆成功之后服务器分配的token(身份令牌),保存到客户端的sessionStorage中
why:
-
项目中除了登陆之外的其他API接口,必须在登录之后(有了身份令牌)才能访问
-
token只应在当前网站打开期间生效,所以将token保存在sessionStorage中,而不是localstorage
(localstorage是持久化的存储机制,sessionStorage是会话期间的存储机制)
-
-
通过编程式导航跳转到后台主页($router.push),路由地址是/home
window.sessionStorage.setItem('token', res.data.token) // 将token保存到sessionStorage中 // 2 通过编程式导航跳转到后台主页($router.push),路由地址是/home this.$router.push('/home')
步骤
-
打印res,出现token
-
F12→application→storage→SessionStorage
-
建立Home.vue
-
router →index.js 导入home
15 路由导航守卫控制页面访问权限
-
F12→application→storage→SessionStorage→登陆后清除token,表示未登录home页→刷新home页面,仍能进入,表示不满足需求(home页面属于有权限页面,登录下才能访问)
-
to将要访问的路径 from从哪个路径跳转而来
-
next是一个函数,表示放行
-
next() 放行 next('/login') 强制跳转
-
-
router/index.js→定义路由后挂载路由导航守卫再export default默认导出
-
16 退出
实现原理:基于token的方式实现退出比较简单,只需要销毁本地的token即可。这样,后续的请求就不会携带token,必须重新登录生成一个新的token之后才可以访问页面。
3.4 语法处理
1 ESLin语法报错(禁用严格模式不报错)
在项目根目录中创建一个配置文件,告诉编辑器在格式化代码时候如何进行相关代码格式化
-
格式化快捷键Ctrl + Alt + L在根目录中创建,prettierrc json格式文件,在里面修改规则
-
到eslint.js中rule规则中禁用
4 主页
4.1 基本布局
-
现在element中导入基本布局组件,注册全局组件
-
取色工具fscapture 复制十六进制HEX
-
element-ui中组件名就是类名
-
页面主题区域撑满屏幕→检查元素,看需要拿个元素撑满全全屏,再自定义类名,取设置样式
4.2 header区域
左右放东西,用flex布局
span 文本标签
<i> 图标项
el-header补充学习:菜鸟教程中css3弹性盒子
display: flex; justify-content //设置弹性盒子元素在主轴(横轴)方向上的对齐方式。 align-items: center; //设置弹性盒子元素在侧轴(纵轴)方向上的对齐方式。
css中嵌套> div {
4.3 导航菜单基本结构
-
到element-ui中找导航菜单
-
到element.js中注册组件
-
更改背景颜色
<el-menu background-color="#333744"
-
梳理结构
4.4 axios拦截器添加token验证
通过接口获取菜单数据
-
除了登录接口之外,其他所有接口必须授权才能正常调用
-
通过axios请求拦截器添加token,保证拥有获取数据的权限
-
到main.js中设置
使用use函数为请求拦截器挂载一个回调函数,只要你向服务器端通过axios发一次数据请求,那么必然会在发送请求期间优先调用use回调函数,比如请求在到达服务器之前,先会调用回调函数对咱们请求做预处理,return config 代表我们已经把这个请求头做了预处理。经处理后请求才会发送到服务器处理
请求拦截器相当于预处理请求过程,这样有权限的API就可以正常调用成功
-
接口文档要求:需要授权的 API ,必须在请求头中使用
Authorization
字段提供token
令牌 -
main.js中添加→F12 →network→Authorization: null(因为是登陆,再登陆其他接口,就是token)
4.5 获取左侧菜单数据
-
接口文档 1.4权限管理1.4.2
-
home.vue定义生命周期函数created() {} :页面一加载的时候就应立即获得左侧菜单
-
async getMenuList () { const { data: res } = await this.$http.get('menus') console.log(res) }
网络请求返回的函数都是promise函数,因为get返回promise,为简化使用await、async ,解构赋值 重命名data为res,打印的res结果
-
数据拿到之后,为了在页面中能渲染出来,将获取到的数据立刻挂载在自己的data中
-
为el-submenu指定唯一的index,每一个菜单应该有独属自己的index值,动态绑定index
-
index="1" 改为 :index="item.id + ''"
4.6 渲染左侧菜单数据
获取的菜单数据存在menulist中,5个一级菜单,children属性下二级菜单
console.log(res)
-
外层for循环渲染一级菜单,内层for循环渲染二级菜单
-
每一个v-for提供一个唯一的key属性
-
每一个菜单都有独属自己的index,绑定动态id,index只接受字符串不接受数值,所以
:index="item.id+''" 加一个空字符串 (循环加:)
-
4.7 为选中项设置字体颜色、分类图标
-
点击后文本颜色改变
active-text-color="#409FFF"
-
二级菜单图标
<i class="el-icon-menu"></i>
-
一级菜单选用第三方字体图标库(assets-demo_fontclass.html找合适的)
-
定义图标对象iconObj
-
每循环一项就有独有id
<i :class="iconObj[item.id]"></i>
-
设置图标与文本间距
在页面中挑选元素
4.8 每次只打开一个边框项并解决边框问题
-
每次只能展开一个菜单项
-
到element-ui 找menu对应的属性住
-
unique-opened="true"
-
优化菜单右侧边框线
-
F12 找到对应修改的样式
-
4.9 实现首页路由的重定向
-
定义welcome组件
-
导入,将welcome作为home子路由规则
-
home重定向welcome
-
在Home的main主体区域放路由占位符,在此展示welcome子组件
4.10 实现侧边栏路由链接的改造
-
为侧边栏开启路由模式router ,
-
跳转地址为 对应:index 因为后端返回的path没有/,需要手动添加
5 用户列表
5.1通过路由的形式展示用户列表组件
点击用户列表链接,在右侧主体区域展示对应的组件
5.1 在sessionStorage中保存左侧菜单的激活状态
-
default-activate,值为对应index
-
将需要激活的链接保存在sessionStorage 中,动态赋值给default-activate
点击链接的时候,把对应的地址保存到sessionStorage 中,当下次刷新页面时候,即home组件刚被创建时候,将值取出来赋值给左侧菜单
-
为每一个二级菜单绑定单击事件
@click="saveNavState('/' + subItem.path)"
-
methods中定义存储状态事件
saveNavState (activePath) { window.sessionStorage.setItem('activePath', activePath) this.activePath = activePath //点击其他链接时更新activePath ,实现高亮效果的动态切换 }
-
data中定义数据,保存激活链接
activePath: ''
-
将此值动态绑定到<el-menu>中的:default-activate(属性前加: 代表属性绑定)
:default-active="activePath"
-
动态赋值,when?整个home组件一被创建的时候(create())
F12->Application->sessionStorage
5.2 绘制列表组件的基本布局结构
-
头部 ——面包屑导航区域
在\assets\css 中定义样式
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) !important;
默认情况下,卡片自带样式权重比较高,要自己的样式覆盖他的样式最好!important
-
栅格系统绘制(Layout)
-
卡片视图组件
el-row(gutter属性指定每一栏之间的间隔) el-col(整个一行宽度是24个格子 :span表示宽度)
5.3 获取用户列表数据
-
发起当前组件的首屏数据请求
created () { this.getUserList() },
类似获取左侧菜单数据
5.4 使用el-able组件渲染基本的用户列表,添加表格索引列
-
:data=" " 绑定数据源
<el-table :data="userlist" border stripe> //添加边框 隔行变色属性
-
模板列 label指定当前页标题,prop当前这一列指向的数据
-
<el-table-column type="index"></el-table-column>
5.5 自定义状态列的显示效果
-
作用域插槽(将共性抽取到组件中,将不同暴露为插槽。)
<template slot-scope="scope"> <el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"> </el-switch> </template>
-
switch开关
通过作用域插槽来渲染 状态这一列:
-
在状态这一列中定义一个作用域插槽
-
通过scope.row获取当前这一行的数据
通过作用域插槽来渲染 操作列:
-
Tooltip文字提示
-
:enterable="false"
false是布尔值,因此在enterable前面加冒号表示数据绑定
-
利用slot-scope接受这个"scope"作用域的数据
5.6 实现分页效果Pagination
// 监听 pagesize 改变的事件 handleSizeChange (newSize) { // console.log(newSize) this.queryInfo.pagesize = newSize this.getUserList() }, // 监听 页码值 改变的事件 handleCurrentChange (newPage) { console.log(newPage) this.queryInfo.pagenum = newPage this.getUserList() // 重新获取页表数据 },
定义事件,监听数据是否改变,去发送数据请求。不同属性配置页码条
5.7 修改用户状态
-
监听switch开关的change事件的改变,拿到改变数据
-
发送ajax请求,调用API接口,保存到数据库中
请求路径:users/:uId/state/:type 冒号开头的一般都是参数
// 监听 switch 开关状态的改变 async userStateChanged (userinfo) { console.log(userinfo) const { data: res } = await this.$http.put( `users/${userinfo.id}/state/${userinfo.mg_state}` //` `模板字符串以拼接动态参数 ) if (res.meta.status !== 200) { userinfo.mg_state = !userinfo.mg_state // 因为没有更改数据库里的状态但是页面上被用户修改了,因此需要取反 return this.$message.error('更新用户状态失败!') } this.$message.success('更新用户状态成功!') },
5.8 实现搜索功能
-
将文本框将data数据作双向绑定
-
查询函数 (后端写的)
-
input输入框自带功能 清空
clearable @clear="getUserList"
6 添加用户
6.1 添加用户的对话框Dialog对话框
-
title 标题
-
控制对话框的显示与隐藏
:visible.sync="addDialogVisible"
6.2 渲染添加用户的表单 Form表单
prop -验证规则属性
-
粘贴 el-form、el-form-item
-
el-form :model 数据绑定对象、:rules 验证规则对象、ref 引用对象、label-width文本宽度
-
el-form-item label 文本、prop 具体的校验规则(在rules做具体定义)
-
el-input v-model做数据双向绑定
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed"> <!-- 内容主体区域 --> <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px"> <el-form-item label="用户名" prop="username"> <el-input v-model="addForm.username"></el-input> </el-form-item>
6.3 自定义校验规则Form表单
-
在data中定义一个箭头函数,代表校验规则
-
在具体的规则中用validator使用自定义规则,trigger定义校验时机
6.4 实现添加表单的重置操作
每次打开都是全新的表单
-
监听对话框的close关闭事件
-
在关闭事件中重置表单(用到$ref引用对象,调用resetFields)
addDialogClosed () { this.$refs.addFormRef.resetFields() }
6.5 表单预校验 调用API接口完成添加用户操作
-
也要拿到整个表单的引用对象
预校验通过,可以发起真正的添加用户的网络请求
-
addUser () { this.$refs.addFormRef.validate(async valid => { if (!valid) return // 可以发起添加用户的网络请求 const { data: res } = await this.$http.post('users', this.addForm) if (res.meta.status !== 201) { this.$message.error('添加用户失败!') } this.$message.success('添加用户成功!') // 隐藏添加用户的对话框 this.addDialogVisible = false // 重新获取用户列表数据 this.getUserList() }) },
7 修改用户
7.1 根据ID查询对应的用户信息
根据ID查询对应的用户信息,保存供我们在表单填充
-
@click="showEditDialog(scope.row.id)"
-
接收到ID,调用API接口,查询到用户信息
-
将查询到的信息保存到editform表单数据对象上
// 展示编辑用户的对话框 async showEditDialog (id) { // console.log(id) const { data: res } = await this.$http.get('users/' + id) if (res.meta.status !== 200) { return this.$message.error('查询用户信息失败!') } this.editForm = res.data this.editDialogVisible = true },
7.2 提交表单完成用户信息
editUserInfo () { this.$refs.editFormRef.validate(async valid => { if (!valid) return // 发起修改用户信息的数据请求 const { data: res } = await this.$http.put( 'users/' + this.editForm.id, { email: this.editForm.email, mobile: this.editForm.mobile } ) if (res.meta.status !== 200) { return this.$message.error('更新用户信息失败!') } // 关闭对话框 this.editDialogVisible = false // 刷新数据列表 this.getUserList() // 提示修改成功 this.$message.success('更新用户信息成功!') }) }
今后修改成功都有 关闭对话框、刷新数据列表、提示修改成功三行代码
7.3 删除用户 MessageBox弹框、调用API 删除
-
按需导入,原型挂载将Message.confirm函数挂载到Vue的原型对象上,名字为$confirm
Vue.prototype.$confirm = MessageBox.confirm
-
在每一个vue组件中都可以通过this.$confirm来弹出一个确认消息的提示框,通过async await简化promise操作,结果定义为confirmResult接受到用户的操作结果
async removeUserById (id) { // 弹框询问用户是否删除数据 const confirmResult = await this.$confirm( '此操作将永久删除该用户, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).catch(err => err) 3.对confirmResult进行if判断 // 如果用户确认删除,则返回值为字符串 confirm // 如果用户取消了删除,则返回值为字符串 cancel // console.log(confirmResult) if (confirmResult !== 'confirm') { return this.$message.info('已取消删除') } // 发送网络请求:参数已经通过removeUserById (id)函数接接收到 const { data: res } = await this.$http.delete('users/' + id) //处理相应结果 if (res.meta.status !== 200) { return this.$message.error('删除用户失败!') } this.$message.success('删除用户成功!') //成功之后刷新数据列表 this.getUserList() },
8 权限列表
-
创建组件->定义对应路由规则
-
什么时候发起data()请求?生命周期函数created中发起这次数据请求
-
渲染全写列表UI结构 border-表格纵向边框线 stripe-隔行变色
<el-table :data="rightsList" border stripe>
-
el-tag 自定义权限等级这一列渲染成什么样子
-
作用域插槽形式来自定义输出格式,用scope接收所有数据
-
注册el-tag标签为全局可用
-
按需展示标签 v-if /v-else-if/v-else判断
-
<el-table-column label="权限等级" prop="level"> <template slot-scope="scope"> <el-tag v-if="scope.row.level === '0'">一级</el-tag> <el-tag type="success" v-else-if="scope.row.level === '1'">二级</el-tag> <el-tag type="warning" v-else>三级</el-tag> </template> </el-table-column>
9 角色列表
通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配一个特定的角色,角色包括不同的功能权限
-
通过路由展示角色列表组件
-
绘制基本布局结构并获取列表数据
-
渲染角色列表数据,设置展开列
<el-table-column type="expand">
-
通过三次for循环渲染三级权限
-
栅格系统布局 el-row
<el-col :span="5"> //占5列 <el-col :span="19"> //占19列
-
美化一级权限的UI结构
将底边框绑定给每一行 <el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id"> :class="[]" //加冒号代表动态数据绑定 i1 //代表索引
-
美化ui结构
-
min-width: 1366px; //当页面不足1366时候,会强制屏幕宽为1366px,不会出现强制换行的问题
-
居中对其:在el-row中添加 display:flex align-item 纵向对齐justify-content 横向对齐
-
点击删除权限按钮弹出确认提示框
-
-
删除角色下指定权限的功能
// this.getRolesList() //删除权限之后 整个下拉菜单会自动合起来 role.children = res.data //服务器返回的最新的权限赋值给角色的children属性
10 分配权限 Tree 树形控件
-
弹出分配权限对话框并请求权限数据
-
初步配置并使用el-tree树形控件
-
优化树形控件的展示效果
-
加载当前角色已有的权限:
-
在点击分配权限按钮的同时,将当前角色身上所有三级权限的id获取出来放到一个数组中,并且把这个数组通过属性绑定交给:default-checked-keys
-
递归函数获取所有三级节点的Id
-
点击分配权限按钮的时候 弹出对话框且获取所有三级节点Id
-
在关闭对话框时重置defKeys数组
-
调用API完成分配权限的功能
const keys = [ ...this.$refs.treeRef.getCheckedKeys(), // 扩展运算符 将一个数组转为用逗号分隔的参数序列,对数组进行解包 ...this.$refs.treeRef.getHalfCheckedKeys() ]
-
点击分配权限按钮时,立刻将当前角色id保存在data中 供我们后续使用
-
在点击确定按钮时候,先获取整个树形结构中半选和全选状态的id值,将他们合并为一个完整的数组
-
接着将得到的数组做了一次字符串的拼接
-
发送网络请求
-
刷新角色列表 关闭分配权限的对话框
-
async allotRights () { const keys = [ ...this.$refs.treeRef.getCheckedKeys(), ...this.$refs.treeRef.getHalfCheckedKeys() ] const idStr = keys.join(',') const { data: res } = await this.$http.post( `roles/${this.roleId}/rights`, { rids: idStr } ) if (res.meta.status !== 200) { return this.$message.error('分配权限失败!') } this.$message.success('分配权限成功!') this.getRolesList() this.setRightDialogVisible = false }
-
-
渲染角色列表的 select下拉菜单
其他人项目运行笔记/运行解决
项目初始化: 1.安装Vue脚手架 2.通过脚手架创建项目 3.配置路由 4.配置Element-UI:在插件中安装,搜索vue-cli-plugin-element 5.配置Axios:在依赖中安装,搜索axios(运行依赖) 6.初始化git仓库 7.将本地项目托管到github或者码云中
后台项目的环境安装配置: 1.安装MySQL数据库:将mydb.sql文件还原到mydb数据库 默认MySQL密码是root 2.安装nodeJS,配置后台项目,从终端打开后台项目vue_api_server 然后在终端中输入命令安装项目依赖包:npm install 并运行node .\app.js将api接口项目跑起来 3.使用Postman测试后台项目接口是否正常(请求登录接口)
vue ui创建项目出现错误Failed to get response from https://...babel helper vue jsx merge props 解决方式: 安装npm install babel-helper-vue-jsx-merge-props --save-dev
安装less依赖:less-loader和less两个
格式化文档和eslint发生冲突 格式规则不一样 可以创建一个文件prettierrc进行配置:如printWidth超过多少字符换行 以符合eslint的规范 也可以关停相应的警告:复制警告的规则 在eslintrc里面进行配置
项目启动时报错Syntax Error: TypeError: this.getOptions is not a function 是因为less-loader 版本过高 需要先卸载再装低版本npm install less-loader@6.0.0 或者不加lang=less也行
Element UI 的标签就是类名 可以直接拿这个设置样式
后台除了登录接口之外,都需要token权限验证,可以通过添加axios请求拦截器来添加token,为请求头加上Authorization属性 值为token,以保证拥有获取数据的权限
layout栅格 总宽度24格
作用域插槽slot-scope,组件如果要根据数据自定义 就要放到作用域插槽里 如权限里的tag
Form表单里的自定义规则
resetFields重置 保存状态
messagebox消息弹框 这个写到方法里面 不是html里面
如果某个函数的返回值是promise 可以用async和await来优化
分类组件里面的下拉表格组件使用插件vue-table-with-tree-grid 先安装 导入 再注册这个组件 (Day4)
按需显示标签 v-if v-else else
级联选择器 父级分类
文本输入框和按钮之间的切换
时间过滤器 将时间以年月日的形式展示 | 管道符
v-model主要是为了让页面上的操作存储到数据里 从而实现双向绑定
安装依赖vue-quill-editor富文本编辑器 然后导入组件并注册
格式转换问题:级联选择器的选中项通过v-model以数组的形式和传递的参数goods_cat绑定了 但是最后传给服务器的时候要字符串形式 但是又不能将其直接改为字符串(正向渲染不出来 会报错)所以要先深拷贝一份总参数对象 安装lodash包 装好依赖后先在本组件里导入(推荐用_接收 类似jquery用$接收)然后调用cloneDeep方法拷贝一份新的对象 在这份新的里面转换好格式再发送给服务器
Timeline时间线组件 element ui 2.6以前的版本是没有的
可视化要安装Echarts依赖 先在report里导入插件 再在mounted里面(不是created)将div初始化为一个echarts实例 合并对象用lodash里的merge方法
生产环境中的项目优化: 1.展示进度条:安装依赖nprogrss 然后在main.js导入两个文件 在request拦截器中显示进度条,在response拦截器中隐藏进度条 2.在serve阶段允许出现console.log 但在build阶段不允许:安装bable-plugin-transform-remove-console(发布时依赖)然后在bable.config.js里面的插件中新增一个transform-remove-console 但是只在发布阶段使用 所以定义一个数组 通过判断process.env.NODE_ENV的值 如果是生产环境则添加这个插件 否则不用这个插件 3.打包报告:记录项目中的错误和其他信息 可以在UI界面中的控制台和分析里面进行查看 饼状图中较大的文件需要减小体积(依赖项)控制台里面打开速度需要优化 资源里面的最大的js文件(1.6M 惊叹号)也需要优化 4.自定义配置(脚手架3)在vue.config.js里面 5.为开发和发布模式指定不同的打包入口:在vue.config.js里面通过chainWebpack修改webpack配置 通过process.env.NODE_ENV的值来设置不同的打包入口 6.设置某些包不合并到js里面 而是在html中以外部CDN的形式导入(如Element UI) 同时将js里面的样式改为html中引入 7.首页定制:开发和发布模式的title显示不一样 先在chainWebpack里面配置isProd 然后title里面根据这个值选择性地渲染标题 那些CDN资源也用这种方式当发布模式才加载上 可以通过build之后生成的dist里面的html里看到最终渲染效果 8.路由懒加载:安装@babel/plugin-syntax-dynamic-import依赖 在babel里面配置好 再将router.js里面的路由改为按需加载
项目上线 1.通过node创建web服务器:在服务包里先初始化npm 再安装express包 将项目里的dist文件夹复制到服务包里 再新建一个app.js 导入express并创建express好服务器 终执行node .\app.js启动服务器 就能在浏览器输入地址查看到项目了 2.开启gzip压缩 减小文件体积 加快传输速度 先安装compression 再导入、注册 打开项目 在network里面可以看到传输的文件大小要小于实际大小 3.配置https服务 让网络传输更加安全 采用https协议对传输的数据进行加密处理 先申请SSL证书FreeSSL.cn 再导入证书 4.pm2管理应用:项目通过在终端运行node .\app.js打开网站 关闭了终端就不能打开了 要想还能打开就要用pm2管理工具 先全局安装pm2 再启动项目pm2 start .\app.js --name zidinyi 此时关闭终端依然能打开网站 要查看运行的项目可打开cmd终端运行pm2 ls 也可停止项目等
练习时出现的问题: 1.serve后出现警告 export 'default' (imported as 'echarts') was not found in 'echarts' 并且项目里出现错误TypeError:Cannot read property 'init' of undefined 解决方法:把import echarts from 'echarts'改为import * as echarts from 'echarts' 2.项目里出现错误'normal' hierarchy in areaStyle has been removed since 4.0. All style properties are configured in areaStyle directly now.echarts版本太老所以从服务器里传来的数据格式不对 areaStyle 里面的normal配置项不用了 直接写在areaStyle 里面就行 3.项目里出现警告(Cate组件中) expand-trigger is removed, use props.expandTrigger
instead. 老版本Element-UI(2.6)中的expand-trigger 菜单的触发方式 新版改为了expandTrigger且要加在下面的cascaderProps里 而不是直接写在标签里。change-on-select is removed, use props.checkStrictly
instead. 老版本(2.6)中change-on-select属性 新版没有了改为checkStrictly(严格的遵守父子节点不互相关联)
改为
不能导入次数过多
yfh补充
1. 打开vue项目目录,shift右键打开Powershell窗口
2. 报错#error More than 1 blank line not allowed no-multiple-empty-lines 删除项目中的空行/关闭eslint
3.报错 imported multiple times import/no-duplicates
![](https://img2020.cnblogs.com/blog/2448090/202112/2448090-20211215222301508-596795182.png)
改为,不能import过多
![](https://img2020.cnblogs.com/blog/2448090/202112/2448090-20211215222504666-555204048.png)
Git
打开项目,先不急写代码,打开终端,查看工作区是否干净
在终端中输入
将本地仓库上传到码云中,如何在码云中新建一个仓库并将仓库做关联
git add . 添加到暂存区: git status -当前工作区是否干净 需要开发一个新的功能在新分支里开发,然后合并到master主分支 git commit -m"完成了登录功能" ——将暂存区的所有代码保存到本地仓库中 -m 后面是描述 git checkout -b login 创建子分支login git branch 查看当前项目所有分支 git checkout master 切换分支到master git merch login 合并login和master代码 git push 本地代码推送到云端 git branch 检查当前所处分支 git checkout -b user 切换到新建分支user上,同时当前所有代码的修改都切换到user子分支上 git status 显示修改文件以及新增文件代码 git add . git status 发现所有文件都被添加到暂存区 git commit -m "完成用户列表功能的开发" 所有代码的修改都已经提交到user子分支,本地仓库更新完成 git status、 git push -u origin user origin代表云端仓库的别名。将本地的user分支推送到云端origin这个仓库中同时以user分支进行保存 git checkout master git branch git merge user 先切换到master主分支,在主分支上合并user分支,代码也更新了 git push -u origin xxx 推送云端的代码 只能从合并master之后推送到云端master
-
初始化git远程仓库
-
创建码云账号并配置SSH公钥
-
首次创建,测试密钥是否可用,
将本地项目托管到Github或码云中
-
新建仓库
-
填写仓库名称,将Readme文件初始化这个仓库去勾
-
全局设置
git config --global user.name "fuhua yi"
新建仓库步骤
1.
2.