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

        我实现的功能是在 element ui 的分页组件中进行分页查询时,如果当前有未保存的修改数据就提示用户,用户可以选择是否放弃未保存的数据。确认放弃就重新查询数据;选择不放弃,不重新查询,并且显示条数选择框保持原样(选择框中文字与选择列表中选择项),页数跳转也是同样的功能。

例子说明:当我们修改了表单某项数据但未保存时。
        更改每页显示条数:我们点击显示条数选择框的 '20条/页',此时会弹出一个提示如图。选择确定就重新查询渲染,未保存数据就丢失了;选择取消的话,不重新查询,并且显示条数保持 '10条/页',打开选择列表也是 '10条/页'。

        页数跳转:我们点击第二页或者下一页按钮,同样跳出提示如图,选择确定就重新查询渲染,未保存数据就丢失了;选择取消的话,不重新查询,并且仍然选中的是第一页。

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

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

动态演示: 

      

        首先我们要如何判断用户修改了表单呢?我采用的方法是在查询数据时,深拷贝一份返回的数组数据。然后在分页改变时对比两者。

 
  
 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 来方便获取。    

 
  



.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();
        }
      }
    },

        最终达到想要的效果:

你可能感兴趣的:(前端,前端,elementui,vue.js)