Fork me on GitHub
余鸢

后台管理开发(二):axios使用及用户页面

用户页面

用户页面基础代码展示,user.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<div class="user-wrap">
<breadcr :meName="meName"></breadcr>
<el-form :inline="true" :model="searchForm">
<el-form-item label="姓名">
<el-input size="small" v-model="searchForm.name$LIKE"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input size="small" v-model="searchForm.username$LIKE"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="search">搜索</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" icon="el-icon-plus" @click="showAndUser">添加用户</el-button>
</el-form-item>
</el-form>
<el-table :data="users" highlight-current-row @current-change="currentChange" height="500" border
style="width: 100%">
<el-table-column sortable prop="name" label="姓名" align="center"></el-table-column>
<el-table-column sortable prop="username" label="用户名" align="center"></el-table-column>
<el-table-column prop="status" label="是否启用" :formatter="formatterColumn" align="center"></el-table-column>
<el-table-column prop="action" label="操作" align="center">
<template slot-scope="scope">
<el-button size="mini" @click="showEditUser(scope.$index,scope.row)" plain>编辑</el-button>
<el-button size="mini" icon="el-icon-edit" type="info" plain @click="showAuthorized">用户赋权</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>

代码分析:

接下来依次分析user.vue的代码。

路径展示区

在用户页面里首先需要展示当前页面的路径,可以快速返回之前的页面。

编写基础组件breadcr.vue

这里用到element-ui的Breadcrumb 面包屑。考虑到在其他页面也要用到次此组件,所以我把Breadcrumb组件抽取出来做基础组件,方便其他页面使用。

组件路径在/base/breadcr/breadcr.vue

1
2
3
4
5
6
7
8
9
<template>
<div class="breadcr-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: '/' }">系统设置</el-breadcrumb-item>
<el-breadcrumb-item>{{meName}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>

在Vue里父组件向子组件中传送数据是通过props实现的。所以我在props里定义属性meName,默认为空,表示菜单名称。

1
2
3
4
5
6
7
8
export default{
props: {
meName: {
type: String,
default: ''
}
}
}

在user.vue组件里注册breadcr组件,并使用它。

1
2
3
4
5
6
7
8
9
10
11
<template>
<div class="user-wrap">
<breadcr></breadcr>
</div>
</template>
export default{
components: {
Breadcr
}
}

我们可以用 v-bind 来动态地将 props 绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件。v-bind的缩写语法是:

在data里声明meName并赋值

1
2
3
4
5
6
7
<breadcr :meName="meName"></breadcr>
data () {
return {
meName: '用户管理',
}
}

页面展示如下(红框部分):

5

搜索区

搜索区使用element-ui的Form表单实现,这里使用行内表单,可以把几个表单放置在一行内,以此来实现我想要的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<el-form :inline="true" :model="searchForm">
<el-form-item label="姓名">
<el-input size="small" v-model="searchForm.name$LIKE"></el-input>
</el-form-item>
<el-form-item label="用户名">
<el-input size="small" v-model="searchForm.username$LIKE"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small">搜索</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" icon="el-icon-plus">添加用户</el-button>
</el-form-item>
</el-form>

:inline设置为true可以让表单域变为行内的表单域,:model表示绑定要输入的搜索数据,所以要在data里搜索数据对象

1
2
3
4
5
6
7
8
9
data() {
return {
// 搜索数据
searchForm: {
name$LIKE: '',
username$LIKE: ''
},
}
}

页面效果如下(红框部分):

6

用户表格区

使用element-ui的Table表格展示用户数据。data表示要显示的数据。

1
2
3
4
5
6
7
8
9
10
11
12
<el-table :data="" highlight-current-row @current-change="currentChange" height="500" border
style="width: 100%">
<el-table-column sortable prop="name" label="姓名" align="center"></el-table-column>
<el-table-column sortable prop="username" label="用户名" align="center"></el-table-column>
<el-table-column prop="status" label="是否启用" :formatter="formatterColumn" align="center"></el-table-column>
<el-table-column prop="action" label="操作" align="center">
<template slot-scope="scope">
<el-button size="mini" @click="showEditUser(scope.$index,scope.row)" plain>编辑</el-button>
<el-button size="mini" icon="el-icon-edit" type="info" plain @click="showAuthorized">用户赋权</el-button>
</template>
</el-table-column>
</el-table>

highlight-current-row表示高亮当前行,同时当表格的当前行发生变化的时候会触发@current-change事件,在data里定义currentRow

1
2
3
4
5
6
7
8
9
10
data() {
return {
currentRow: null,
}
},
methods: {
currentChange (val) {
this.currentRow = val
},
}

跨域请求数据

使用axios跨域请求数据

不同域名之间的访问,需要跨域才能正确请求。我们的项目是前后端分离,存在跨域问题。Vue-cli 创建的项目,可以直接利用 Node.js 代理服务器,实现跨域请求,我使用axios解决跨域。

axios简介

vue2.0官方推荐axios进行ajax请求。axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

  • 从浏览器中创建 XMLHttpRequest
  • 从 node.js 发出 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防止 CSRF/XSRF

废话不多说,直接开始使用

安装axios

1
npm install axios

封装axios方法

一般情况下,我们会用到的方法有:GET,POST,PUT,PATCH,DELETE,封装方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import axios from 'axios'
import Vue from 'vue'
let v = new Vue()
axios.defaults.withCredentials = true
axios.defaults.baseURL = '/api'
axios.create({
headers: {'content-type': 'application/x-www-form-urlencoded'}
})
// 添加一个响应拦截器
axios.interceptors.response.use((response) => {
if (response.data && response.data.errcode) {
if (parseInt(response.data.errcode) === 40001) {
console.log('未登录')
// 未登录
v.$emit('go', '/')
}
}
return response
}, error => {
return Promise.reject(error)
})
export const POST = (url, params) => {
return axios.post(url, params).then(res => res.data)
}
export const GET = (url, params) => {
return axios.get(url, params).then(res => JSON.stringify(res.data))
}
export const PUT = (url, params) => {
return axios.put(url, params).then(res => res.data)
}
export const DELETE = (url, params) => {
return axios.delete(url, params).then(res => res.data)
}
export const PATCH = (url, params) => {
return axios.patch(url, params).then(res => res.data)
}

设置代理

在config/index.js文件中修改dev中的proxyTable

1
2
3
4
5
6
7
8
9
proxyTable: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}

其中 ‘/api’ 为匹配项,target 为被请求的地址,因为在 ajax 的 url 中加了前缀 ‘/api’,而原本的接口是没有这个前缀的,所以需要通过 pathRewrite 来重写地址,将前缀 ‘/api’ 转为 ‘/‘,如果本身的接口地址就有 ‘/api’ 这种通用前缀,就可以把 pathRewrite 删掉。

获取用户列表

这里我把用户相关的操作代码放在api文件下,使用时方便查找一目了然。

api/user.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import * as API from './index'
export function getUser () {
const url = '/user'
const data = Object.assign({}, {
pageIndex: 0,
pageSize: 10,
sortField: '',
sortOrder: ''
})
return API.GET(url, {
params: data
}).then((res) => {
return Promise.resolve(JSON.parse(res))
})
}

现在引入封装好的axios文件,执行GET请求,给出url和所需参数,url是接口地址。这里url='/user'而不是url='/api/user',是因为我在index.js文件里设置axios.defaults.baseURL = '/api',使用 axios可以全局配置一个 baseURL,所以无需再加上/api

user.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
import { getUser } from 'api/user'
import { statusCode } from 'common/js/config'
methods: {
_getUerList () {
getUser().then((res) => {
if (res.status === statusCode) {
// console.log(res.result.data)
this.users = res.result.data
}
})
}
}

引入api/user.js文件,调用getUser()方法,判断response的状态码,如果正确,控制台输出用户列表,截图如下:

7

想要在页面展示数据,首先在data中定义users对象,默认为[],同时设置:data="users",在table表格内填充数据。

1
2
3
4
5
6
7
<el-table :data="users" highlight-current-row @current-change="currentChange" height="500" border style="width: 100%">
data() {
return {
users: []
}
}

截图如下:

8

用户数据成功展示,完美~!

搜索

前面已经创建搜索数据对象,接下来对搜索按钮进行操作,点击搜索按钮触发search事件。

1
2
3
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="search">搜索</el-button>
</el-form-item>

在api/user.js里创建searchUser(),调用GET方法

api/user.js

1
2
3
4
5
6
7
8
9
export function searchUser (queryParams, queryParamsIndex) {
const url = '/user'
const data = Object.assign({}, queryParams, queryParamsIndex)
return API.GET(url, {
params: data
}).then((res) => {
return Promise.resolve(JSON.parse(res))
})
}

同样user.vue引入searchUser()方法。这里需要注意下,因为后台给出的数据与所得出的数据不同,需要先对数据处理得出我们想要的数据结构。数据处理方法可能会在其他组件中用到,所以我把它放在common包下,代码如下:

common/js/utils.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function encodeQueryParam (data) {
let queryParam = {}
let index = 0
let temp = ''
for (let f in data) {
if (data[f] === '') continue
if (f.indexOf('$LIKE') !== -1 && data[f].indexOf('%') === -1) temp = '%' + data[f] + '%'
if (f.indexOf('$START') !== -1) temp = '%' + data[f]
if (f.indexOf('$END') !== -1) temp = data[f] + '%'
queryParam['terms[' + (index) + '].column'] = f
queryParam['terms[' + (index) + '].value'] = temp
temp = ''
index++
}
return queryParam
}

user.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { encodeQueryParam } from 'common/js/utils'
search () {
this.total = 0
this.pageIndex = 1
this.searchUser()
},
searchUser () {
let that = this
let queryParams = {
name: encodeQueryParam(that.searchForm)
}
let queryParamsPage = {
pageIndex: that.pageIndex,
pageSize: that.pageSize,
sortField: '',
sortOrder: ''
}
searchUser(queryParams.name, queryParamsPage).then((res) => {
if (res.status === statusCode) {
that.total = res.total
this.users = res.result.data
// this.users = that.data
}
}).catch((error) => {
console.log(error)
that.$message.error({
message: '请求出现异常',
duration: 2000
})
})
},

截图效果如下:

9

添加用户

对添加用户按钮进行操作,点击添加用户按钮触发showAndUser事件。

1
2
3
<el-form-item>
<el-button type="primary" size="small" icon="el-icon-plus" @click="showAndUser">添加用户</el-button>
</el-form-item>

添加用户页面我使用element-ui里的Dialog 对话框来实现,点击按钮弹出添加用户页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--添加用户页面-->
<el-dialog title="添加用户" :visible.sync="dialogFormVisible" center>
<el-form :model="addForm" ref="addForm">
<el-form-item label="姓名:" :label-width="formLabelWidth">
<el-input v-model="addForm.name" auto-complete="off" style="width: 240px"></el-input>
</el-form-item>
<el-form-item label="用户名:" :label-width="formLabelWidth">
<el-input v-model="addForm.username" auto-complete="off" style="width: 240px"></el-input>
</el-form-item>
<el-form-item label="密码:" :label-width="formLabelWidth">
<el-input v-model="addForm.password" auto-complete="off" style="width: 240px"></el-input>
</el-form-item>
<el-form-item label="备注:" :label-width="formLabelWidth">
<el-input type="textarea" v-model="addForm.describe"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="saveUser">保存</el-button>
</div>
</el-dialog>

:visible.sync="dialogFormVisible"表示是否显示 Dialog,同时在data里定义dialogFormVisible,默认为false,表示是否显示添加页面。定义addForm对象表示添加数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data() {
return {
// 添加相关数据
dialogFormVisible: false, // 添加页面是否显示
addForm: {
name: '',
username: '',
password: '',
describe: ''
},
addFormRules: {
name: [{required: true, message: '请输入姓名', trigger: 'blur'}],
username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
password: [{required: true, message: '请输入密码', trigger: 'blur'}],
describe: [{required: true, message: '备注', trigger: 'blur'}]
}
}
}

调用POST请求

api/user.js

1
2
3
export function addUser (userParams) {
return API.POST('/user', userParams)
}

user.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
showAndUser () {
this.dialogFormVisible = true
this.addForm = {
name: '',
username: '',
password: '',
describe: ''
}
},
saveUser () {
let that = this
this.$refs.addForm.validate((valid) => {
if (valid) {
this.$confirm('确定保存吗?', '提示', {}).then(() => {
let userParams = Object.assign({}, this.addForm)
addUser(userParams).then((res) => {
if (res.status === statusCode) {
that.$message.success({
message: '添加用户成功',
duration: 2000
})
that.$refs['addForm'].resetFields()
that.dialogFormVisible = false
that.search()
} else {
that.$message.error({
message: '添加用户失败',
duration: 2000
})
}
}).catch((error) => {
console.log(error)
that.$message.error({
showClose: true,
message: '请求出现异常',
duration: 2000
})
})
})
}
})
},

页面展示:

10

具体代码看:https://github.com/hs-web/hsweb-ui-vue