表单界面涉及到数据的操作,会有几个关键点
index.vue文件解析
<template>
<div>
<!-- 条件查询 -->
<el-form/>
<!-- 表格 -->
<el-table/>
<!-- 分页组件 -->
<el-pagination/>
<!-- 弹框 -->
<Edit/>
</div>
</template>
<script>
import api from "@/api/category"; //接口
import Edit from "./edit"; //弹窗
export default {
// 注册后使用
components: {
Edit,
},
data() {
return {}
},
// 钩子函数获取数据
created() {
this.fetchData();
},
//方法
methods: {
}
}
</script>
列表接口
请求URL: /article/category/search
请求方式: post
描述:文章类别分页条件查询列表
Api 调用接口
import request from '@/utils/request'
export default {
//分类查询列表
getList(query, current = 1, size = 20) {
return request({
url: `/article/category/search`,
method: 'post',
data: {
...query,
current,
size
}
})
}
}
<template>
</template>
<script>
import api from '@/api/category'
export default {
data() { return {
list: [], page: { // 分页相关
total: 0, // 总记录数
current: 1, // 当前页码
size: 20, // 每页显示20条数据,
},
query: {} // 查询条件
}
},
// 钩子函数获取数据
created () {
this.fetchData()
},
methods: {
async fetchData() {
const { data } = await api.getList(
this.query,
this.page.current,
this.page.size
);
this.list = data.records;
this.page.total = data.total;
},
}
</script>
列表模板
列表参考:https://element.eleme.cn/#/zh-CN/component/table 链接: link.<template>
<div>
<el-table stripe :data="list" border style="width: 100%">
<el-table-column align="center" width="60px" type="index" label="序号">
el-table-column>
<el-table-column align="center" prop="name" label="分类名称">
el-table-column>
<el-table-column align="center" prop="sort" label="排序">
el-table-column>
<el-table-column align="center" prop="remark" label="备注">
el-table-column>
<el-table-column align="center" prop="status" label="状态">
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status ? "正常" : "禁用" }}
el-tag>
template>
el-table-column>
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button
type="primary"
@click="handleEdit(scope.row.id)"
size="mini"
>编辑el-button
>
<el-button
type="danger"
@click="handleDelete(scope.row.id)"
size="mini"
>删除el-button
>
template>
el-table-column>
el-table>
div>
template>
methods
选项中添加 handleEdit
编辑和 handleDelete
删除方法,后面需要使用。methods: { fetchData () {
api.getList(this.query, this.page.current, this.page.size).then(response => {
// console.log(response)
this.list = response.data.records
this.page.total = response.data.total })
}
,handleEdit(id) {
console.log('编辑', id)
},
handleDelete(id) {
console.log('删除', id)
},
}
状态码转名称
渲染后发现状态码,我们将状态列以转为名称,并且使用
标签包裹,其中通过 filters
选项来定义过滤器来实现样式转换。
参考: https://element.eleme.cn/#/zh-CN/component/tag 链接: link.
statusFilter
过滤器转换样式export default {
filters: { statusFilter(status) {
// 样式 在这里插入代码片
const statusMap = {0: 'danger', 1: 'success'}
// status等于0返回danger, 1返回success
return statusMap[status] } },
//....
}
methods
选项中添加 handleEdit
编辑和 handleDelete
删除方法,后面需要使用。methods: {
fetchData () {
api.getList(this.query, this.page.current, this.page.size).then(response => {
// console.log(response)
this.list = response.data.records
this.page.total = response.data.total }) },
handleEdit(id) { console.log('编辑', id) },
handleDelete(id) { console.log('删除', id) }, }
分页查询实现
div
里面。因为 template
里面只能有唯一根节点
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page.current"
:page-sizes="[10, 20, 50]"
:page-size="page.size"
layout="total, sizes, prev, pager, next, jumper"
:total="page.total"
>
el-pagination>
methods
选项中定义 handleSizeChange
每页条目数改变后触发的方法,和 handleCurrentChange
页面改变后触发的方法。methods: {
// 当每页显示条数改变后,被触发 , val是最新的每页显示条数
handleSizeChange(val) {
this.page.size = val this.fetchData()
},// 当页码改变后,被触发 , val 是最新的页面
handleCurrentChange(val) {
this.page.current = val this.fetchData()
},
// ...
}
条件查询实现
在列表上方添加查询功能。
Form 表单参考 :https://element.eleme.cn/#/zh-CN/component/form#xing-nei-biao-dan链接: link.
Select选择器:https://element.eleme.cn/#/zh-CN/component/select 链接: link.
<el-form
:inline="true"
:model="query"
size="mini">
<el-form-item label="分类名称:">
<el-input v-model.trim="query.name">el-input>
el-form-item>
<el-form-item label="状态:" >
<el-select v-model="query.status" clearable filterable style="width: 85px">
<el-option v-for="item in statusOptions" :key="item.code" :label="item.name" :value="item.code">
el-option>
el-select>
el-form-item>
<el-form-item>
<el-button icon='el-icon-search' type="primary" @click="queryData">查询el-button>
<el-button icon='el-icon-refresh' class="filter-item" @click="reload">重置el-button> <el-button type="primary" size="mini" icon="el-icon-circle-plus-outline" >新增el- button>
el-form-item>
el-form>
payTypeOptions
用于状态下拉框,并在 data
选项声明与赋值 payTypeOptions
属性。<script> import api from '@/api/category' // 用于下拉框
const statusOptions = [
{code: 0, name: '禁用'},
{code: 1, name: '正常'} ]
export default { data() {
return {
list: [],
page: {// 分页相关
total: 0, // 总记录数
current: 1, // 当前页码
size: 20, // 每页显示20条数据,
},
query: {}, // 查询条件
statusOptions, //状态下拉框
}
},
methods
声明 queryData
查询方法 , 主要是把 this.page.current
当前页面变为 1methods: {
// 查询
queryData() {
// 将页码变为第1页
this.page.current = 1 this.fetchData()
},
methods
选项中添加 reload
方法,模板中触发调用此方法methods: {
// 重置 or 刷新当前页面
reload() {
this.query = {}
this.fetchData()
},
// ...
}
新增窗口实现
新增和修改功能共用一个组件,我们将它作为子组件引入到列表查询父组件中,下面先将组件定义出来。
弹出功能参考:https://element.eleme.cn/#/zh-CN/component/dialog#zi-ding-yi-nei-rong 链接: link.
el-dialog
标答属性 title
窗口标题, visible.sync
是否弹出窗口
注意其中包含多行文本编辑框。
<template>
<el-dialog
:title="title"
:visible.sync="visible"
width="500px"
:before-close="handleClose"
>
<el-form
ref="formData"
:model="formData"
label-width="100px"
label-position="right"
style="width: 400px"
>
<el-form-item label="分类名称:" prop="name">
<el-input v-model="formData.name">el-input>
el-form-item>
<el-form-item label="状态:" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :label="1" value="1">正常el-radio>
<el-radio :label="0" value="0">禁用el-radio>
el-radio-group>
el-form-item>
<el-form-item label="排序:" prop="sort">
<el-input-number
v-model="formData.sort"
:min="1"
:max="10000"
style="width: 295px"
>el-input-number>
el-form-item>
<el-form-item label="备注:" prop="remark">
<el-input type="textarea" v-model="formData.remark">el-input>
el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('formData')"
>确定el-button
>
<el-button @click="handleClose">取消el-button>
el-form-item>
el-form>
el-dialog>
template>
注意:每个 el-form-item 不要少了 prop ,不然清空不了数据。
<script> export default {
// 接收父组件传递的属性
props: {
visible: {
//弹出隐藏
type: Boolean,
default: false
},
title: {
// 标题
type: String,
default: ''
},
formData: {
// 表单数据
type: Object,
default: {}
},
remoteClose: Function // 用于关闭窗口
},
methods: {
// 关闭弹窗
handleClose(done) { },//提交表单
submitForm(formName) { },
}
}
</script>
列表引用新增组件
在父组件 category/index.vue 引用 category/edit.vue 子组件实现弹窗
components
选项引用为子组件<script>
import api from '@/api/category'
import Edit from './edit'
export default {
components: {
Edit
},
//...
}
</script>
子组件 <template> <div >
<!-- 条件查询 -->
<!-- 数据列表 -->
<!-- 分页组件 -->
<!-- 新增与编辑组件 -->
<Edit
:title="edit.title"
:visible="edit.visible"
:formData="edit.formData"
:remoteClose="remoteClose"
/>
</div>
</template>
data
选项中声明传递给子组件的属性、方法<script>
import api from '@/api/category'
import Edit from './edit'
export default {
components: { Edit },
data() {
return { //...
edit: { // 子组件中引用
title: '',
visible: false,
formData: {}
}
}
},
methods: { // 触发关闭弹出的新增修改子组件窗口
remoteClose() {
}, } }
</script>
@click="openAdd"
弹出窗口<el-button
icon="el-icon-circle-plus-outline"
type="primary"
@click="openAdd"
>新增
el-button>
methods: {
//打开新增窗口
openAdd() {
this.edit.visible = true;
this.edit.title = "新增";
},
//...
}
el-form-item
标签的 prop
属性中指定字段名, 不然有时间会输入框输入不了,如果还是输入不了,在 index.vue 组件中的 edit.formData
中将字段名指定出来data() {
return {
edit: { // 子组件中引用
title: '',
visible: false,
formData: {
id: null,
name: '',
sort: null,
remark: '' }
}}
}
关闭弹出窗口
当点击 取消 按钮或者右上角 X 将关闭窗口
this.visible = false
关闭窗口,因为它是父组件传递过来的,子组件不能直接改。// 关闭弹窗
handleClose(done) {
//this.visible = false错误的,因为它是父组件传递过来的,子组件不能直接改
},
remoteClose
方法来关闭窗口。remoteClose
,并重置清空表单数据methods: {
// 关闭弹窗
handleClose(done) {
// 表单清空
this.$refs['formData'].resetFields()
// this.visible
// 错误的,因为它是父组件传递过来的,子组件不能直接改 // 因为 visible 是父组件的属性,所以要让父组件去改变值
this.remoteClose() },
//提交表单
submitForm(formName) {
}, }
this.edit.visiable=false
关闭窗口,刷新数据。methods: {
//打开新增窗口
openAdd() {
this.edit.visible = true this.edit.title = '新增' },// 触发关闭弹出的新增修改子组件窗口
remoteClose() { // 一定要加上这个,不然有时候表单输入不了值
this.edit.formData = {} t
his.edit.visible = false
this.fetchData()
}
校验表单数据
el-form
上绑定属性 :rules="rules"
<template>
<el-dialog
:title="title"
:visible.sync="visible"
:before-close="handleClose"
width="500px">
rules
属性进行校验 data() {
return {
rules: {
// porp值
name: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
status: [
{ required: true, message: "请输入分类名称", trigger: "change" },
],
sort: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
},
};
},
提交表单数据
当点击新增窗口中的确认按钮时, 提交表单数据,后台API服务接口响应新增成功或失败。
请求URL: /article/category
请求方式: post
Api 调用接口
add(data) {
return request({
url: `/article/category`,
method: 'post',
data
})
},
submitForm
方法中判断校验是否通过,通过了则调用 submitData
异步方法提交数据,代码如下:注意: async submitData(){}
不要少了前面的 async
<script> import api from '@/api/category'
export default {
//...,
methods: {
// ...
//2. 提交表单
// 2.提交表单数据
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 校验通过,提交表单数据
this.submitData();
} else {
// 校验不通过
return false;
}
});
},
//3. 异步方法提交数据
async submitData() {
let response = null;
if (this.formData.id) {
//编辑
response = await api.update(this.formData);
} else {
//新增
response = await api.add(this.formData);
}
// 等上面返回数据response后再进行处理
if (response.code === 20000) {
// 提交成功, 关闭窗口, 刷新列表
this.$message({
showClose: true,
message: "保存成功",
type: "success",
});
// 关闭窗口
this.handleClose();
} else {
this.$message({
showClose: true,
message: "保存失败",
type: "error",
});
}
},
script>
当点击 编辑 按钮后,弹出编辑窗口,并查询出分类相关信息进行渲染。修改后点击 确定 提交修改后的数据。
添加查询数据
请求URL: /article/category/{id}
请求方式: get
描述:通过类别 ID 查询数据接口
添加提交修改数据
请求URL: /article/category
请求方式: put
描述:类别数据更新
Api 调用接口回显数据
getById
和 更新方法 update
// 查询类别详情
getById(id) {
return request({
url: `/article/category/${id}`,
method: 'get'
})
},
//更新
update(data) {
return request({
url: `/article/category`,
method: 'put',
data
})
},
handleEdit
方法做如下修改:再特别强调下是 index.vue,不是 edit.vue handleEdit(id) {
//通过id查询详情
api.getById(id).then((response) => {
if (response.code === 20000) {
// 将查询的详情传递
this.edit.formData = response.data;
this.edit.title = "编辑";
this.edit.visible = true;
}
});
},
提交修改后的数据
在 src/views/category/edit.vue 组件中的 submitData
方法加上一个判断 this.formData.id
存在则为更新,否则是新增操作。
// 提交表单数据
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 校验通过,提交表单数据
this.submitData();
} else {
// 校验不通过
return false;
}
});
},
// 异步方法提交数据
async submitData() {
let response = null;
if (this.formData.id) {
//编辑
response = await api.update(this.formData);
} else {
//新增
response = await api.add(this.formData);
}
// 等上面返回数据response后再进行处理
if (response.code === 20000) {
// 提交成功, 关闭窗口, 刷新列表
this.$message({
showClose: true,
message: "保存成功",
type: "success",
});
// 关闭窗口
this.handleClose();
} else {
this.$message({
showClose: true,
message: "保存失败",
type: "error",
});
}
},
},
};
当点击删除按钮后, 弹出提示框,点击确定后,执行删除并刷新列表数据
确认消息弹框参考:https://element.eleme.cn/#/zh-CN/component/message-box#que-ren-xiao-xi 链接: link.
删除接口
请求URL: /article/category/{id}
请求方式: delete
描述:根据ID删除类别
Api 调用接口
deleteById
方法 //删除
deleteById(id) {
return request({
url: `/article/category/${id}`,//单反引号
method: 'delete',// delete 方式提交
})
},
handleDelete
方法做如下修改:// 删除
handleDelete(id) {
this.$confirm('确认删除这条记录吗?', '提示', { confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'}).then(() => {
// 确认
api.deleteById(id).then(response => {
//提示信息
this.$message({ type: response.code===20000 ? 'success':'error',
message: response.message
})
// 刷新列表
this.fetchData() }) }).catch(() => {
// 取消删除,不理会
})
}
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button
type="primary"
@click="handleEdit(scope.row.id)"
size="mini"
>编辑el-button
>
<el-button
type="danger"
@click="handleDelete(scope.row.id)"
size="mini"
>删除el-button
>
template>
el-table-column>
category/index.vue
<template>
<div>
<!-- 条件查询 -->
<el-form :inline="true" :model="query" size="small ">
<el-form-item label="分类名称">
<el-input v-model="query.name" placeholder="审批人"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-select
v-model="query.status"
clearable
filterable
style="width: 85px"
>
<el-option label="正常" value="1"></el-option>
<el-option label="禁用" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" type="primary" @click="queryData"
>查询</el-button
>
<el-button icon="el-icon-refresh" @click="reload">重置</el-button>
<el-button
icon="el-icon-circle-plus-outline"
type="primary"
@click="openAdd"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table stripe :data="list" border style="width: 100%">
<el-table-column align="center" width="60px" type="index" label="序号">
</el-table-column>
<el-table-column align="center" prop="name" label="分类名称">
</el-table-column>
<el-table-column align="center" prop="sort" label="排序">
</el-table-column>
<el-table-column align="center" prop="remark" label="备注">
</el-table-column>
<el-table-column align="center" prop="status" label="状态">
<template slot-scope="scope">
<el-tag :type="scope.row.status | statusFilter">
{{ scope.row.status ? "正常" : "禁用" }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button
type="primary"
@click="handleEdit(scope.row.id)"
size="mini"
>编辑</el-button
>
<el-button
type="danger"
@click="handleDelete(scope.row.id)"
size="mini"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page.current"
:page-sizes="[10, 20, 50]"
:page-size="page.size"
layout="total, sizes, prev, pager, next, jumper"
:total="page.total"
>
</el-pagination>
<!-- 弹框 -->
<Edit
:title="edit.title"
:visible="edit.visible"
:formData="edit.formData"
:remoteClose="remoteClose"
/>
</div>
</template>
<script>
import api from "@/api/category";
import Edit from "./edit";
export default {
name: "Category", //和对应路由表中配置的name值一致
components: {
Edit,
},
data() {
return {
query: {}, //查询条件
list: [],
page: {
current: 1, //当前页码
size: 20, //每页显示多少条
total: 0, //总计录数
},
// statusOptions, // 状态下拉框数组
edit: {
title: "",
visible: false,
formData: {},
},
};
},
filters: {
statusFilter(status) {
// 0 禁用,1 正常
const statusMap = { 0: "danger", 1: "success" };
return statusMap[status];
},
},
created() {
this.fetchData();
},
methods: {
fetchData() {
api
.getList(this.query, this.page.current, this.page.size)
.then((response) => {
this.list = response.data.records;
this.page.total = response.data.total;
});
},
handleEdit(id) {
//通过id查询详情
api.getById(id).then((response) => {
if (response.code === 20000) {
// 将查询的详情传递
this.edit.formData = response.data;
this.edit.title = "编辑";
this.edit.visible = true;
}
});
},
//删除
handleDelete(id) {
this.$confirm("确认删除这条记录吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
// 发送删除请求
api.deleteById(id).then((response) => {
this.$message({
type: response.code === 20000 ? "success" : "error",
message: response.message,
});
});
//刷新列表数据
this.fetchData();
})
.catch(() => {
//取消删除,不用理会
});
},
//val 是切换之后的每页显示多少条
handleSizeChange(val) {
this.page.size = val;
this.fetchData();
},
handleCurrentChange(val) {
this.page.current = val;
this.fetchData();
},
// 条件查询
queryData() {
//将页码变为1,第1页
this.page.current;
this.fetchData();
},
//重置
reload() {
this.query = {};
this.fetchData();
},
// 关闭窗口
remoteClose() {
this.edit.formData = {};
this.edit.visible = false;
this.fetchData();
},
// 点击新增
openAdd() {
this.edit.visible = true;
this.edit.title = "新增";
},
},
};
</script>
category/edit.vue
<template>
<el-dialog
:title="title"
:visible.sync="visible"
width="500px"
:before-close="handleClose"
>
<el-form
:rules="rules"
ref="formData"
:model="formData"
label-width="100px"
label-position="right"
style="width: 400px"
>
<el-form-item label="分类名称:" prop="name">
<el-input v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="状态:" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :label="1" value="1">正常</el-radio>
<el-radio :label="0" value="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="排序:" prop="sort">
<el-input-number
v-model="formData.sort"
:min="1"
:max="10000"
style="width: 295px"
></el-input-number>
</el-form-item>
<el-form-item label="备注:" prop="remark">
<el-input type="textarea" v-model="formData.remark"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('formData')"
>确定</el-button
>
<el-button @click="handleClose">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script>
import api from "@/api/category";
export default {
props: {
//弹窗标题
title: {
type: String,
default: "",
},
// 弹出窗口,true弹出
visible: {
type: Boolean,
default: false,
},
// 提交表单数据
formData: {
type: Object,
default: {},
},
remoteClose: Function, // 用于关闭窗口
},
data() {
return {
rules: {
// porp值
name: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
status: [
{ required: true, message: "请输入分类名称", trigger: "change" },
],
sort: [{ required: true, message: "请输入分类名称", trigger: "blur" }],
},
};
},
methods: {
// 关闭窗口
handleClose() {
this.$refs["formData"].resetFields();
// 注意不可以通过 this.visble = false 来关闭,因为它是父组件的属性
this.remoteClose();
},
// 提交表单数据
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 校验通过,提交表单数据
this.submitData();
} else {
// 校验不通过
return false;
}
});
},
// 异步方法提交数据
async submitData() {
let response = null;
if (this.formData.id) {
//编辑
response = await api.update(this.formData);
} else {
//新增
response = await api.add(this.formData);
}
// 等上面返回数据response后再进行处理
if (response.code === 20000) {
// 提交成功, 关闭窗口, 刷新列表
this.$message({
showClose: true,
message: "保存成功",
type: "success",
});
// 关闭窗口
this.handleClose();
} else {
this.$message({
showClose: true,
message: "保存失败",
type: "error",
});
}
},
},
};
</script>
<style>
</style>
api/category.js
import request from '@/utils/request'
export default {
//分类查询列表
getList(query, current = 1, size = 20) {
return request({
url: `/article/category/search`,
method: 'post',
data: {
...query,
current,
size
}
})
},
add(data) {
return request({
url: `/article/category`,
method: 'post',
data
})
},
// 查询类别详情
getById(id) {
return request({
url: `/article/category/${id}`,
method: 'get'
})
},
//更新
update(data) {
return request({
url: `/article/category`,
method: 'put',
data
})
},
//删除
deleteById(id) {
return request({
url: `/article/category/${id}`,
method: 'delete',
})
},
// 查询类别详情
getNormalList() {
return request({
url: `/article/category/list`,
method: 'get'
})
},
// 获取所有正常状态的分类和标签
getCategoryAndLabel() {
return request({
url: `/article/category/label/list`,
method: 'get'
})
},
}