我实现的功能是在 element ui 的分页组件中进行分页查询时,如果当前有未保存的修改数据就提示用户,用户可以选择是否放弃未保存的数据。确认放弃就重新查询数据;选择不放弃,不重新查询,并且显示条数选择框保持原样(选择框中文字与选择列表中选择项),页数跳转也是同样的功能。
例子说明:当我们修改了表单某项数据但未保存时。
更改每页显示条数:我们点击显示条数选择框的 '20条/页',此时会弹出一个提示如图。选择确定就重新查询渲染,未保存数据就丢失了;选择取消的话,不重新查询,并且显示条数保持 '10条/页',打开选择列表也是 '10条/页'。页数跳转:我们点击第二页或者下一页按钮,同样跳出提示如图,选择确定就重新查询渲染,未保存数据就丢失了;选择取消的话,不重新查询,并且仍然选中的是第一页。
动态演示:
首先我们要如何判断用户修改了表单呢?我采用的方法是在查询数据时,深拷贝一份返回的数组数据。然后在分页改变时对比两者。
<el-pagination
@size-change="handleSizeChange"
@current-change="handlePageChange"
:current-page.sync="currentPage"
:page-sizes="[10, 20, 40, 80]"
:page-size="pageSize"
:total="totalCount"
layout="sizes, prev, pager, next"
>
</el-pagination>
data() {
return {
currentPage: 1,
cachedPage: 1,
pageSize: 10,
cachedPageSize: 10,
totalCount: 0,
loading: false, // 是否显示加载中
originalData: [],
formData: {
tableData: [],
rules: {}
}
}
},
methods: {
handleSizeChange(val) {
if (!this.isEqual()) {
this.$confirm("当前有未保存数据,确定要继续吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.cachedPageSize = val;
this.pageSize = val;
this.getData();
}).catch(() => {
this.pageSize = this.cachedPageSize;
})
} else {
this.cachedPageSize = val;
this.pageSize = val;
this.getData();
}
},
handlePageChange(val) {
if (!this.isEqual()) {
this.$confirm("当前有未保存数据,确定要继续吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.cachedPage = val;
this.currentPage = val;
this.getData();
}).catch(() => {
this.currentPage = this.cachedPage;
})
} else {
this.cachedPage = val;
this.currentPage = val;
this.getData();
}
},
// 判断表单数据是否改变
isEqual() {
for (let i in this.formData.tableData) {
const obj = this.formData.tableData[i];
for (let key in obj)
if (obj[key] === "") obj[key] = null;
// 属性值为null经过修改再删除会变为"",故将两者看做相等
}
const newData = this.formData.tableData.map((obj) => {
const newObj = Object.assign({}, obj);
delete newObj.changed; // changed是告诉后端那些项修改了 对比时要删除
return newObj;
})
return JSON.stringify(newData) === JSON.stringify(this.formData.tableData);
},
async getData() {
const isLoading = this.loading("加载中");
const params = {
page: this.currentPage,
page_size: this.pageSize
}
const { code, data, count } = await getDataList(params); // 请求列表数据
if (code == 200) {
this.originalData = JSON.parse(JSON.stringify(data));
this.$set(this.formData, "tableData", data);
this.totalCount = count;
isLoading.close();
}
}
}
这样修改后,页数跳转可以恢复原来的页数,但是 '条/页' 没有恢复。
又从F12里查找对应 dom 元素尝试进行修改,获取 el-pagination 的引用,并且给分页选择框加上类属性 one 来方便获取。
<el-pagination
ref="pagination"
@size-change="handleSizeChange"
@current-change="handlePageChange"
:current-page.sync="currentPage"
:page-sizes="[10, 20, 40, 80]"
:page-size="pageSize"
:total="totalCount"
layout="sizes, prev, pager, next"
:popper-class="'one'"
>
</el-pagination>
.catch(() => {
this.pageSize = this.cachedPageSize;
const pagination = this.$refs.pagination;
const select = pagination.$el.querySelector(".one .el-input__inner");
select.value = `${this.cachedPageSize}条/页`;
const ul = document.querySelector(".el-select-fropdown__list");
const fn = () => {
const lis = ul.querySelectorAll("li");
lis.forEach(li => {
li.classList.remove("selected");
})
const arr = [10, 20, 40, 80];
let index = arr.indexOf(this.pageSize);
let changedLi = lis[index];
changedLi.classList.add("selected");
}
fn();
ul.addEventListener("mouseover", fn);
})
结果显示看着是符合的,但是选择 '20条/页' 后取消,应该是 '10条/页' 无法点击,'20条/页' 可以点击,但是结果是 '10条/页' 可以点, '20条/页' 无法点,即虽然改变了样式,但是 element ui 仍然认为我们点击了 '20条/页',现在处于 '20条/页'。
感觉只能去修改 element ui 的源码逻辑了,否则无法满足我的需求;要么就自己写一个分页组件。这时,我突然想到正常的每页显示条数我们每次点击后,不是会自己自动跳转到对应的 '条/页' 吗。于是想到了我直接将对应原来的 '条/页' 的 li 标签触发一次 click ,然后跳过提示弹框与重新请求数据不就好了吗?
data中新增 changedFlag: false,
handleSizeChange(val) {
if (!this.changedFlag && !this.isEqual()) {
this.$confirm("当前有未保存数据,确定要继续吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.cachedPageSize = val
this.pageSize = val
this.getData()
}).catch(() => {
this.pageSize = this.cachedPageSize;
const ul = document.querySelector(".one .el-select-fropdown__list");
const lis = ul.querySelectorAll("li");
const arr = [10, 20, 40, 80];
let index = arr.indexOf(this.pageSize);
let changedLi = lis[index];
this.changedFlag = true;
changedLi.click();
})
} else { // 判断是否是changedLi触发click
if (this.cachedPageSize == val) {
this.changedFlag = false;
this.pageSize = val
}
else {
this.changedFlag = false;
this.cachedPageSize = val;
this.pageSize = val;
this.getData();
}
}
},
最终达到想要的效果: