element-ui table数据表格实现与坑点记录
怎么查看项目依赖了哪些文件和版本
- 找到与
src
同级目录的package.json
- 再找到
devDependencies
查看即可
js变量不存在则给予默认值
this.total = res.total || 0; // 赋值总条数,当不存在total属性时,total属性赋为默认值0
模态框坑点
- 添加和修改共用一个模态框,且提交完表单后,需要重置模态框表单的字段值为空对象
- 否则添加模态框、修改页面、该条数据都会受到影响
- 需要自定义一个变量来确认是走 添加接口 还是 修改接口,此处变量使用的是
modalType
- 修改模态框内,赋值不能直接使用
this.row = row
,这涉及到深拷贝,会影响到该条数据 - 添加和修改共用一个模态框,使用不当时,极有可能出现“点击编辑栏后,再点击添加栏,表单数据没被清空依旧存在等问题”,解决方案是表单回显给数据赋值的时候写到this.$nextTick里面。表单清空写在dialog关闭前面。
原因:
1 this.$refs['xxx'].resetFields()这个做法其实是重置表单到初始值,不是清空表单,当表单第一次在页面中渲染时所用的数据就是初始数据。
2 this.$refs[xxx]必须要在dialog显示之后再调用,否则会找不到这个元素报错。
接口坑点
- 无论请求哪个接口,都要使用
.catch((err)=>{console.log(err)})
进行兜底捕获异常,不然页面会产生验证报错,影响体验 - 后端使用tp返回接口时,可能PHP内部逻辑错误,导致前台显示跨域错误
携带参数请求接口坑点
post方式携参请求
直接传参params,作为第二参数即可
// 获取用户数据列表
export const getUser = (params) => {
return axios.post(`${url}index`, params);
}
get方式携参请求
直接传参params,需要创建一个对象{},对象名伟params,对象值为对params进行解构赋值的{...params}作为第二参数
// 获取用户数据列表
export const getUser = (params) => {
return axios.get(`${url}index`, {
params: { ...params }
});
}
获取列表数据坑点
以下几处,需要调用获取列表数据接口,获取最新数据
- 表单模态框添加完数据后
- 表单模态框修改完数据后
- 数据表格删除数据后
页码坑点
以下几处,需要将页码变量重置为1
- 搜索栏携参搜索search方法,获取列表数据时
- 切换每页展示条数limit时
- page-sizes的起始页码必须绑定limit变量,否则会产生分页逻辑错误
- total、page-size、current-page、page-sizes必须在el-pagination分页组件中声明且绑定变量
否则会出现查询数据为空现象,这是因为在同等条件下,没有找到相应页码的数据
例如符合条件的数据一共只能分2页,偏偏此处没有重置页码为1,而是传递了第6页作为参数,自然就找不到了
完整代码
<template>
<div class="manage">
<!-- 模态框 -->
<el-dialog
:title="title"
center
:visible.sync="dialogVisible"
:before-close="handleClose"
width="50%"
>
<el-form
:model="form"
ref="form"
label-width="100px"
:inline="true"
:rules="rules"
>
<el-form-item label="姓名" prop="username">
<el-input v-model="form.username" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="分数" prop="score">
<el-input v-model="form.score" placeholder="请输入分数"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="生日" prop="birthday">
<el-col>
<el-form-item prop="birthday">
<el-date-picker
type="date"
placeholder="选择生日"
v-model="form.birthday"
style="width: 100%"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="等级" prop="level">
<el-input v-model="form.level" placeholder="请输入等级"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="submit">确 定</el-button>
</span>
</el-dialog>
<!-- 头部操作栏 -->
<div class="manage-header">
<el-button type="primary" @click="handleAdd">+ 新增</el-button>
<el-button @click="multipleDel()" type="danger">多选删除</el-button>
<el-button @click="toggleSelection()">取消选中</el-button>
<el-form
ref="userform"
:model="userform"
label-width="70px"
:inline="true"
class="userForm"
>
<el-form-item label="姓名" prop="username">
<el-input v-model="userform.username"></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="userform.sex" placeholder="请选择性别">
<el-option label="男" value="1"></el-option>
<el-option label="女" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="生日" prop="birthday">
<el-date-picker
v-model="userform.birthday"
type="daterange"
align="right"
unlink-panels
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
>
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="warning" @click="search">搜索</el-button>
<el-button @click="resetForm">清空</el-button>
</el-form-item>
</el-form>
</div>
<!-- 数据表格 -->
<div class="table">
<el-card class="tableCard" shadow="hover">
<el-table
:data="list"
ref="list"
v-loading="loading"
style="width: 100%"
stripe
border
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column prop="id" label="ID"> </el-table-column>
<el-table-column prop="username" label="姓名"> </el-table-column>
<el-table-column prop="sex" label="性别">
<template slot-scope="scope">
<span style="margin-left: 10px">
{{ scope.row.sex == 1 ? "男" : "女" }}
</span>
</template>
</el-table-column>
<el-table-column prop="level" label="等级"> </el-table-column>
<el-table-column prop="score" label="分数"> </el-table-column>
<el-table-column prop="birthday" label="生日"> </el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
type="success"
size="mini"
@click="handleEdit(scope.row)"
>编辑</el-button
>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.row.id)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 分页 -->
<div class="pagination">
<el-pagination
:page-sizes="[limit, 7, 9, 11]"
:current-page="page"
:page-size="limit"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
prev-text="上一页"
next-text="下一页"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:hide-on-single-page="true"
>
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import { getUser, addUser, editUser, delUser } from "../api/user/index";
export default {
data() {
return {
//当只有一页时隐藏分页
isShow: false,
// 加载动画
loading: true,
// 数据列表
list: [],
// 每页展示条数
limit: 5,
// 默认当前页码
page: 1,
// 数据列表总数据
total: 0,
// 模态框的值,用于判断是走入add还是edit逻辑
modalType: false,
// 模态框的显示隐藏控制
dialogVisible: false,
// 搜索栏表单字段信息
userform: {
username: "",
birthday: [],
// score: "",
sex: "",
// level: "",
},
// 搜索栏的日期时间选择快捷处理
pickerOptions: {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
},
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
},
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
},
},
],
},
// 模态框表单字段信息
form: {
username: "",
birthday: "",
score: "",
sex: "",
level: "",
},
// 模态框表单字段的验证规则
rules: {
username: [{ required: true, message: "请输入姓名" }],
birthday: [{ required: true, message: "请选择生日" }],
score: [{ required: true, message: "请输入分数" }],
sex: [{ required: true, message: "请输入性别" }],
level: [{ required: true, message: "请输入等级" }],
},
};
},
computed: {
title() {
return this.modalType ? "修改" : "添加";
},
},
methods: {
// 搜索表单
search() {
// 重置页码
this.initPage();
// 拿到最新数据
this.handleList(this.userform);
},
// 重置搜索表单字段
resetForm() {
this.$refs.userform.resetFields();
// 拿到最新数据
this.handleList();
},
// 多选删除
multipleDel() {
const selection = this.$refs.list.selection;
const ids = [];
selection.map((obj) => {
ids.push(obj.id);
});
this.handleDelete(ids);
},
// 取消表格checkbox选中
toggleSelection() {
this.$refs.list.clearSelection();
},
// 表单提交
submit() {
// 使用element-ui的表单验证方法,得到验证后结果值和验证失败的对象
this.$refs.form.validate((res, obj) => {
// 验证通过
if (res) {
// 根据modalType值来判断走入add还是edit
if (this.modalType) {
// edit----传参进行ajax请求
editUser(this.form).then((res) => {
this.handleSuccess(res);
});
} else {
// add----传参进行ajax请求
addUser(this.form).then((res) => {
this.handleSuccess(res);
});
}
}
});
},
// 处理API成功响应回来的逻辑
handleSuccess(res) {
// 响应码判断
if (200 == res.code) {
// 成功提示
this.$message({
showClose: true,
center: true,
message: res.msg,
type: "success",
duration: 1500,
});
// 关闭弹窗
this.handleClose();
// add/edit后,都需要刷新列表,拿到最新的数据
this.handleList();
}
},
// 关闭模态框,重置form表单字段值
handleClose() {
this.dialogVisible = false;
// this.$refs["form"].resetFields();
this.$nextTick(() => {
for (let key in this.form) {
this.form[key] = "";
}
this.$refs["form"].clearValidate();
});
for (let key in this.form) {
this.form[key] = "";
}
this.$refs["form"].clearValidate();
},
// 取消表单,清空所有字段值
cancel() {
this.handleClose();
},
// 增加
handleAdd() {
// 开启弹窗
this.dialogVisible = true;
// 赋值模态框类型为true,提供ajax提交时判断是add
this.modalType = false;
console.log("测试编辑后再点击添加是否还有值", this.form.username);
},
// 删除
handleDelete(id) {
this.$confirm("确定删除吗?", "提示信息", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
delUser({ id: id }).then((res) => {
this.$message({
showClose: true,
center: true,
message: res.msg,
type: "success",
duration: 1500,
});
this.handleList();
});
})
.catch((err) => {
console.log(err);
});
},
// 编辑
handleEdit(row) {
// 开启弹窗
this.dialogVisible = true;
// 赋值模态框类型为true,提供ajax提交时判断是edit
this.modalType = true;
// 深拷贝赋值,让dialog框有值渲染,不能直接浅拷贝赋值this.form = row,否则会影响到add时候的弹窗
this.form = JSON.parse(JSON.stringify(row));
},
// 查询
handleList(param) {
// 默认分页查询参数
const defaultPageInfo = { page: this.page, limit: this.limit };
/*
传入了额外参数,则将额外参数与搜索栏参数、分页查询参数合并组成查询条件
否则直接使用搜索栏参数、分页查询参数合并作为查询条件
*/
const data = param
? { ...param, ...this.userform, ...defaultPageInfo }
: { ...defaultPageInfo, ...this.userform };
// 携带参数进行请求
getUser(data)
.then((res) => {
// 赋值表格数据列表,以供渲染
this.list = res.data;
// 赋值总条数,当不存在total属性时赋值为0
this.total = res.total || 0;
// 取消过渡加载动画
this.loading = false;
})
.catch((err) => {
console.log(err);
});
},
// 每页展示条数变化
handleSizeChange(val) {
this.limit = val;
// 每次切换展示条数时,都要重置页码为1。否则会出现明明有数据却因为页码错误导致的api返回空数据
this.initPage();
// 开启过渡加载动画
this.loading = true;
this.handleList();
},
// 当前页码变化
handleCurrentChange(val) {
this.page = val;
// 开启过渡加载动画
this.loading = true;
this.handleList();
},
// 初始化页码
initPage() {
this.page = 1;
},
},
created() {
this.handleList();
},
};
</script>
<style lang="less" scoped>
.manage {
height: 100%;
}
.userForm {
margin-top: 30px;
}
.table {
position: relative;
.pagination {
position: absolute;
right: 0;
margin-top: 20px;
}
}
</style>