提升Element UI分页查询用户体验与交互:实现修改未保存提示

我实现的功能是在 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();
        }
      }
    },

最终达到想要的效果:

相关推荐
路多辛2 小时前
为什么我要做一个开发者工具箱?聊聊 Kairoa 的诞生
前端·后端
jerryinwuhan2 小时前
理论及算法_时间抽取论文
前端·算法·easyui
秋子aria2 小时前
模块的原理及使用
前端·javascript
菜市口的跳脚长颌2 小时前
一个 Vite 打包配置,引发的问题—— global: 'globalThis'
前端·vue.js·vite
胖虎2652 小时前
实现无缝滚动无滚动条的 Element UI 表格(附完整代码)
前端·vue.js
小左OvO2 小时前
基于百度地图JSAPI Three的城市公交客流可视化(一)——线路客流
前端
星链引擎2 小时前
企业级智能聊天机器人 核心实现与场景落地
前端
GalaxyPokemon2 小时前
PlayerFeedback 插件开发日志
java·服务器·前端
爱加班的猫2 小时前
深入理解防抖与节流
前端·javascript
自由日记2 小时前
学习中小牢骚1
前端·javascript·css