vue实战
学习视频链接:Vue实战项目:电商管理系统(Element-UI)
1.项目概述
1.功能模块
电商后台管理系统大致可以分为以下几个功能模块:
- 用户登录,退出登录
- 用户管理
- 权限管理
- 角色列表
- 权限列表
- 商品管理
- 商品列表
- 分类列表
- 参数管理
- 订单管理
- 数据管理
2.开发模式
采用的开发模式是前后端分离的开发模式。其中前端项目是基于Vue
技术栈的SPA(单页面应用)项目。
前端技术栈主要有:
- vue
- vue-router
- Element-UI
- Axios
- Echarts
后端技术栈主要有:
- Node.js
- Express
- Jwt(状态保持的工具)
- Mysql(Ajax)
- Sequelize(操作数据库的框架)
2.项目初始化
1.创建项目
用vue图形化界面创建一个新项目:
第一步:Win+R,输入cmd并在命令行中输入vue ui
。
第二步:选择创建一个新项目,如下图:
第三步:选择手动配置项目,如下图:
第四步:接着进入功能界面,把Choose vue version,Babel,Router,Linter/Formatter,使用配置文件这几项打勾即可。如下图:
第五步:最后来到配置界面,按照下图配置即可:
最后点击创建即可。
2.配置ElementUI
创建完成之后,会出现一个新界面,选择插件-添加插件-搜索vue-cli-plugin-element然后选中并下载即可安装ElementUI依赖:
把完整的全部导入改成按需导入:
3.配置Axios
选择依赖-安装依赖-搜索axios并选中点击安装依赖:
注意,安装到的是运行依赖。
至此为止,项目初始化已经基本完成。
3.git托管
1.配置ssh公钥
怎么生成ssh公钥看这里:生成ssh公钥
生成完成之后添加到ssh公钥即可。之后在终端输入
ssh -T git@gitee.com
即可检验是否添加完成(如果出现Hi,xxx…successful就表明成功了)。
2.托管到仓库
在码云新建一个仓库vue_shop,然后在新页面中会出现一个Git 全局设置,在终端分别执行一下那两段代码即可。
接着进入到项目目录,在此处打开终端,输入命令:git status
查看一下状态。然后执行git add .
和git commit -m "add files"
这两个命令做一下本地的提交(提交到暂存区)。最后再查看一下状态,如下图:
至此为止,仅仅是在本地操作仓库。上传到云端仓库的话,还需要两条命令(参照自己新建完仓库之后的最后两条命令):
git remote add origin git@gitee.com:yeyongzhi1023/vue_shop.git
git push -u origin master
再刷新一下码云上新建仓库后的页面即可看到代码已经上传到云端仓库了。
4.后台环境配置
1.安装Mysql数据库
可以去网上下载一个PHPstudy来进行后端环境的配置。
注意,PHPstudy自带数据库,它与本地的数据库不是同一个。因此在下载之后可能会占用本地数据库的端口3306,所以有必要时可以改一下PHPstudy自带的端口号(3306->3309)。具体请参考:PHPstudy修改端口号避免占用。
本地数据库的启动/停止方法:控制面板-系统和安全-管理工具-服务,找到Mysql然后启动此服务即可。
PHPstudy自带数据库的启动/停止方法:图形化界面点击按钮即可。
本地数据库的安装位置一般是:
C:\Program Files\MySQL
PHPstudy自带数据库的安装位置一般是:phpStudy\phpstudy_pro\Extensions\MySQL5.7.26\bin
如果找不到安装位置,打开Mysql终端输入命令:show variables like "%char%";
(带分号)即可。
一切准备就绪之后就可以执行一下sql文件了,资源链接在此:源码以及资源。
这个链接是在B占学习视频的评论下面找到的。评论里有好多资源,API接口文档的链接,自行摸索即可。
sql文件的位置在:17-21 Vue.js项目实战开发\20-21vue电商\3.vue-项目实战day1\素材\vue_api_server\db
。执行sql文件的话用SQLyog或者Navicat等工具都可以。执行前先建立一个数据库名叫mydb
。执行完成之后去phpStudy\phpstudy_pro\Extensions\MySQL5.7.26\data\mydb
里面查看,如果有文件了说明数据库还原成功了。
2.配置后端API接口服务器
在17-21 Vue.js项目实战开发\20-21vue电商\3.vue-项目实战day1\素材\vue_api_server
中的该文件夹就是后端接口的位置,在此处打开终端先执行命令:npm install
下载一下依赖包。然后执行:node app.js
将后端运行起来。
注意,运行后端之前要注意自己的数据库的端口号和密码(像上面我已经把端口号改成3309了,数据库的密码也改了)。做过修改的话就需要
vue_api_server\config\default.json
里面把对应的数据给改掉。
接着用Postman(一款接口测试工具,文件夹里有)进行接口测试(用户名密码随意即可),如下图:
成功的用户名和密码是admin和123456。如下图:
token
是用来保存登录状态的,类似于session
。
5.登录模块
因为项目的前端运行和服务器后端运行在不同的接口,存在跨域问题,因此保持登录状态需要用到token。
1.登录-token原理分析
在登陆页面,客户端输入用户名,密码之后发送给服务器端,服务器端验证成功后把该用户的token值返回给客户端,客户端将token保存在本地,接着客户端后续的每一次请求都要携带该token值以此来确认该操作是由哪个用户发出的。
2.登陆页面的布局
用编辑器打开之前创建好的项目vue_shop
,然后打开终端运行一下git status
检查一下工作区是否干净。
在做每一个功能的时候,最好都在主分支branch master的基础上创建一个子分支。
创建并切换到子分支login的命令为:
git checkout -b login
查看当前全部分支的命令:
git branch
同创建项目时一样,启动项目也可以采用图形化界面来启动,输入命令vue ui
即可。然后选择任务-serve-启动serve-等编译成功后启动app即可看到运行界面。如下图:
启动完成之后把一些原本的页面给清除干净,并且把一些没用的文件给删掉:
App.vue
:
<template>
<div id="app">
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
</style>
router/index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
]
})
export default router
3.逻辑功能的实现
完成布局之后就是数据绑定(将用户名密码随着用户输入同步保存在变量中),数据验证(鼠标一离开数据源就对数据进行校验),**重置功能(resetFields()方法)**等等。
开发注意事项
1.开发过程中会碰到许多语法报错,因为之前在创建项目的时候选择了校验语法格式。开发过程中碰到一些依赖例如less,less-loader没有安装的,可以在图形化操作界面选择依赖-开发依赖进行搜索安装,然后重启serve和app。
2.因为之前安装ElementUI时选择的不是全部导入而是按需导入,因此在编写登录时的表单组件的时候需要在plugins文件夹下的element.js中导入所需要的组件。然后再注册成为全局组件。千万要注意语法格式,引入组件只需要在一个import中完成,组件后和不要加空格,最后要空一行出来…如下所示:
import Vue from 'vue'
import { Button, Form, FormItem, Input } from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
3.需要用到图标的话,如果ElementUI中找不到合适的可以用第三方的图标库,例如阿里的矢量图标库。具体使用方法请看:vue+Element-ui快餐店pos系统中的第二部分项目图标。
4.编写登录逻辑的时候,请求方法返回得到的结果如果是一个Promise对象那么,就需要加上async
和await
(await只能用在被async修饰的函数之中),如下所示:
login () {
this.$refs.loginFormRef.validate(async valid => {
// valid 就是验证的结果(boolean类型)
// console.log(valid)
if (!valid) return
const result = await this.$http.post('login', this.loginForm)
console.log(result)
})
}
5.路由导航守卫:就是当没有登陆的时候,为了避免用户直接在地址栏中输入/home从而跳转到主页面的操作,需要守卫来进行保护。具体代码如下:
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next() 放行函数
if (to.path === '/login') return next()
// 获取token
// 除了访问登录页不受权限限制以外,其余页面都需要登陆后才能跳转
const tokenStr = window.sessionStorage.getItem('token')
if (!tokenStr) return next('/login')
next()
})
6.在一开始创建项目的时候,因为我们选择了自动校验ESLint的语法格式,所以编译过程中经常会报语法格式错误。并且ESlint和自己本身的格式化配置有冲突,可能会导致语法混乱。解决办法:配置.prettierrc
文件。
首先在项目的根目录下创建一个文件,叫.prettierrc
(它是一个JSON类型的文件),然后将下面代码复制到里面。
{
"semi": false, // 使用分号, 默认true
"singleQuote": true, // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
}
还有许多格式属性和值可以自行百度搜索。
保存之后并且配置默认格式规则是Prettier
即可(可能还需要安装一个插件Prettier - Code formatter
),如下图:
完成之后在代码中右键-格式化文档就可以将代码进行规范来保证和ESlint语法不冲突。
当然还有另外的解决办法就是直接在根源把错误给禁止掉,例如错误space-before-function-paren
:方法的括号前和括号后都需要加空格,实在是很不人性化。想直接把它禁用,方法如下:
找到项目根目录下的.eslintrc.js
文件,在里面的rules字段中增加一条语句:
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'space-before-function-paren': 0 //增加的语句
}
完成之后重新进行编译就不会再发出警告了。
至此为止登录功能模块已经基本完成。
4.上传代码
新建一个终端,输入git status
查看代码状态,发现有一些文件是被修改过了的,有一些文件是新增加的。然后执行git add .
将代码全部上传到暂存区,接着执行git commit -m "完成了登录退出功能"
上传代码到本地仓库。
输入git branch
,显示当前分支是login
,因此我们处于login分支
,刚才git commit
提交的文件都被放在了login分支
,接下去就是把login分支
的所有代码更新并且合并到master主分支
。
第一步:切换回主分支master
git checkout master
注意,切回主分支后,之前新建的那几个
Login.vue
和Home.vue
会消失,因为它们不在主分支下,还未同步过来。
接着执行下面这行命令,将login分支的代码同步过来:
git merge login
如下图:
最后一步就是将代码推送到云端仓库中:
git push
注意,完成之后代码就同步到云端了。在本地我们有两个分支,分别是login和master,但是在云端只有一个默认分支master(可以在云端仓库中找到)。所以还需要把子分支login推送到云端仓库中。
分别执行以下命令:
git checkout login //切换回login分支
git branch //查看当前分支
git push -u origin login //推送login子分支
今后写完某个功能的代码以后都要遵循以下步骤:
- 上传到本地仓库
- 合并到主分支master
- 将主分支master推送到云端仓库
- 将子分支推送到云端仓库
6.主页布局
整体布局分为顶部的标题信息,侧边导航栏和右侧内容区。如下图所示:
注意,布局中的标签,例如
<el-header></el-header>
,它们默认的类名就是标签名,因此不需要加class属性,直接用类名选择器.el-header即可编辑这个标签的css样式。
需要授权的API,必须在请求头中使用Authorization字段提供的token令牌。
之前讲过除了登录的API 接口,别的全部接口请求时都需要携带token值,具体方法是:通过axios请求拦截器添加token,保证拥有获取数据的权限。代码如下:
main.js
axios.interceptors.request.use(config => {
config.headers.Authorization = window.sessionStorage.getItem('token')
return config
})
7.左侧菜单栏
注意,在通过v-for
双层循环编写左侧菜单栏的时候,index属性也要进行动态绑定,否则当你点开第一个一级菜单的时候,其余的一级菜单全部都会打开。如下所示:
<!-- 一级菜单 -->
<el-submenu :index="item.id +' '" v-for="item in menulist" :key="item.id">
<!-- 一级菜单的模板区域 -->
<template slot="title">
<!-- 导航图标 -->
<i class="el-icon-location"></i>
<!-- 导航文本 -->
<span>{{ item.authName }}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item :index="subitem.id +' '" v-for="subitem in item.children" :key="subitem.id">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{ subitem.authName }}</span>
</template>
</el-menu-item>
</el-submenu>
要注意,
:index="item.id +' '"
不要写成:index="item.id" +" "
。否则会报错。
注意事项
1.如果发现页面上有一些细微的地方css有冲突,右键网页检查然后修改掉对应的css样式即可。
2.在设置一些标签的属性值时,如果值是boolean类型,那么需要将该属性进行动态绑定(属性名前面加上冒号),例如在设置左侧菜单栏的展开折叠动画关闭的时候,代码如下:
<el-menu unique-opened :collapse="isCollapse" :collapse-transition="false" background-color="#333744" text-color="#fff" active-text-color="#409EFF">
3.在左侧菜单栏的展开折叠变换的时候,整个左侧侧边栏的宽度也要随着菜单栏的展开折叠进行动态变化,因此:
<el-aside :width="isCollapse ? '64px' : '200px'">
4.想要实现左侧二级菜单的点击激活高亮显示功能,需要执行以下几步:
- 为二级菜单添加点击事件,当点击时将跳转链接(路由)保存到sessionStorage中。并在data中新建一个变量activePath将跳转链接(路由)也进行保存。
- 同时将菜单的
default-active
属性设置为动态变化,例如:default-active="activePath"
。 - 同时,在生命周期函数created()中也要进行设置:
this.activePath = window.sessionStorage.getItem('activePath')
,目的是当返回主页时能保存之前的激活状态。
8.用户管理-用户列表
1.在渲染表格中的用户状态的时候,从数据库中获取到的值是boolean类型,但是在页面上显示的是一个Switch开关,这时候需要用到模板语言template:
<el-table-column label="状态">
<template slot-scope="scope">
<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"></el-switch>
</template>
</el-table-column>
模板语言就是让el-switch标签的显示内容根据**整行元素对象的某个属性(这里每一行代表了一个对象,根据的是该对象的mg_state属性即用户状态)**来对应显示。
2.当表格数据渲染完成后,如果需要内容居中,可以用以下方法:
<el-table ..(此处省略其他属性).. :cell-style="rowClass" :header-cell-style="headClass">
...
</el-table>
...
methods: {
// 表头样式设置
headClass () {
return 'text-align: center;'
},
// 表格样式设置
rowClass () {
return 'text-align: center;'
},
}
3.在设置用户状态的时候,当修改用户状态失败时,要在前端把用户的状态给改回来否则显示的是修改后的状态,但是此次修改并没有成功,所以需要在页面上改回原来的状态。如下所示:
if (res.meta.status !== 200) {
userinfo.mg_state = !userinfo.mg_state
return this.$message.error('修改用户状态失败!')
}
4.在实现搜索功能的时候,当翻页到第二页时,再次查询第一页中的用户数据会查询不到。另外,在实际中,搜索功能应该是全局的,即可以按用户名搜索,也可以按邮箱来搜索…。实现办法可以将全局搜索集成在一个输入框中,或者布局多个对应类型的输入框来进行全局搜索。
5.添加用户的表单的重置操作:即当关闭添加用户的弹出对话框时,将表单的数据全部清空,避免下一次再次打开表单时仍然残留上一次的数据和校验信息。
6.在编写编辑用户信息弹出对话框的时候,方法是点击编辑按钮时将用户的id(scope.row.id)
作为参数传递过去,在通过axios的get
请求到用户信息。但是,因为scope.row
本身就携带这该对象的数据,为什么还需要再请求一遍呢?因为再查询一遍会保证获取到的是最新的信息。并且,当数据字段中存在最近修改时间等属性时,这些属性不会在scope.row
中携带(因为这些属性不需要在表格中显示),这时候直接传scope.row
会导致数据修改不全面。
7.在根据用户id删除用户时的确认弹窗中,代码如下:
const confirmResult = await this.$confirm('确定将此用户删除吗', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
console.log(confirmResult)
但是这样写当你在弹框中选择取消的时候会报错,因此需要增加catch
捕获错误。代码如下:
const confirmResult = await this.$confirm('确定将此用户删除吗', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
console.log(confirmResult)
上传代码
新建一个user分支并切换到uesr分支:
git checkout -b user
检查一下当前分支:
git branch
检查一下文件状态:
git status
提交文件到本地暂存区
git add .
再次检查文件状态
git status
提交代码到本地仓库:
git commit -m '完成用户列表功能'
再次检查文件状态
git status
将本地的user分支推送到云端仓库:
git push -u origin user
检查一下当前分支:
git branch
切换回主分支:
git checkout master
同步本地仓库的user分支的代码到主分支:
git merge user
将本地的master主分支推送到云端:
git push