前端实现搜索分页添加功能

2,916 阅读2分钟

项目需要前端对数据进行表格展示,并且能够增添数据、编辑数据,以及对表格能够查询、重置以及分页。

这里均使用element-ui,不详细叙述 tamplate 写法。

本文的实现:在搜索态的时候,是不支持添加的;在编辑态的时候,不支持搜索。

表格数据的添加

​ 添加数据采取了子组件 dialog 添加,在添加后,将数据传给父组件。

​ 整个过程分为以下几步:

  1. ​ 对 dialog 数据进行校验;
  2. ​ 校验之后关闭 dialog,并且将数据给到 tableDataCopy(用来备份表格数据,方便切换搜索态和正常态)
  3. ​ 将值push到 tableData;
  4. ​ 调取分页的函数,重新分页,重新计算总页数。
handleSave() {
      // 校验
      this.$refs.form.validate((valid, invalidFields) => {
        if (valid) {
          // 关闭dialog
          this.dialogVisible = false;
          // 给表格数据,此时也会备份数据,在监听中写入
          this.tableData.push(JSON.parse(JSON.stringify(this.addDialogForm)));
          // 分页
          this.handlePagination();
          // 重置dialog
          this.addDialogForm = {
            codeSeqNum: '',
            codeName: '',
            codeIdentifier: '',
            details: [
              {
                codeKey: '',
                codeValue: ''
              }
            ]
          };
        }
      });
    }

编辑数据

​ 由于在编辑态和正常态切换时,就是 span 和 input 之间的切换,input 就要涉及到校验,因此选择了表单嵌套表格,用 editable 标志位切换 span 和 input,二者绑定的值相同。

<el-table-column label="标识名称" prop="codeName">
    <template slot-scope="scope">
      <h-add-form-item-row
        v-show="editable"
        :prop="`rowFormData[${scope.$index}].codeName`"
        :rules="codeRules.input"
      >
        <el-input
          v-show="editable"
          v-model.trim="scope.row.codeName"
          autofocus
          size="small"
        ></el-input>
      </h-add-form-item-row>
      <span v-show="!editable">{{ scope.row.codeName }}</span>
    </template>
  </el-table-column>

表格分页

​ 表格分页利用了 el-pagination 标签。

需要注意的是,current-page.sync 写入 sync 关键字,

如果不写入,会导致修改当前页current-page后 ,current-change事件不触发

即当强制令页面回到第一页,this.currentPage = 1,current-change事件不触发,el-pagination的高亮渲染不变,可能还处于其他页。

<el-pagination
  :current-page.sync="currentPage"
  :page-size="20"
  layout="total, prev, pager, next"
  :total="total"
  :before-current-change="beforeCurrentChange"
  @current-change="handleCurrentChange"
></el-pagination>

初始分页

handlePagination() {
  // 回到初始页,重新计算数据总数,表格总页数
  this.currentPage = 1;
  this.total = this.tableData.length;
  this.totalpage = Math.ceil(this.total / 20);
  this.addFormItemRow.rowFormData =
    this.total > 20 ? this.tableData.slice(0, 20) : this.tableData;
},

当前页改变触发该函数

handleCurrentChange(val) {
  // 主要判断当前页是否是最后一页
  this.addFormItemRow.rowFormData =
    val === this.totalpage
      ? this.tableData.slice((val - 1) * 20, this.total)
      : this.tableData.slice((val - 1) * 20, val * 20);
},

​ 因为涉及到编辑,希望编辑状态是不能翻页的,编辑状态和搜索状态共存时,不按保存按钮无法确定该页面编辑的数据是否希望保存。

​ 因此在翻页前做了判断,判断是不是编辑态。

// 翻页前的钩子函数
beforeCurrentChange(val) {
  if (this.editable) {
    this.$message({
      message: '请先保存再翻页!',
      type: 'warning'
    });
    return false;
  } else {
    return true;
  }
},

搜索及重置

​ 前端做搜索,由于搜索结果和原数据的展示用到的是同一个 table 标签来展示及操作,那其中重要的一步是对原始数据进行备份,方便连续多次搜索。

注:在搜索态的时候,是不支持添加的;在编辑态的时候,不支持搜索。

​ 搜索需要注意几个部分:

  1. ​ 对输入的字符串进行 trim 处理,去除前后空格;
  2. ​ 对输入的英文字符串搜索时,应该不区分大小写;
  3. ​ 条件单独搜索、组合搜索需要实现;
  4. ​ 注意连续多次的搜索。
  5. ​ 需要提前备份数据
// 代码增添了searchButtonFlag,搜索标志位,在搜索态时为true,其他为false
// 深度监听tableData,此时监听的有可能是原数据,也有可能是搜索结果
// 利用 searchButtonFlag 判断,在不是搜索态的时候,将table的表格做备份(方便同步编辑态数据)
// 这样做由于 tableData 初始为空,后台给到数据,tableData变化,数据备份
watch: {
    tableData: {
      // 深度监听
      handler(val, oldVal) {
        if (!this.searchButtonFlag) {
          this.tableDataCopy = JSON.parse(JSON.stringify(this.tableData));
        }
      },
      deep: true
    },
  },

​ 搜索,就是对数组元素的匹配,主要利用 filter 函数和 indexOf 来查找即可。

​ 搜索结束,需要重新分页。

// 搜索函数
handleSearchPage() {
  this.searchButtonFlag = true;
  // 搜索字段
  const codeName = this.search.codeName;
  const codeIdentifier = this.search.codeIdentifier.toLowerCase();
  if (codeName !== '' || codeIdentifier !== '') {
    this.tableData = this.tableDataCopy.filter(function(item) {
      return codeName === ''
        ? item.codeIdentifier.toLowerCase().indexOf(codeIdentifier) !== -1
        : codeIdentifier === ''
        ? item.codeName.indexOf(codeName) !== -1
        : item.codeName.indexOf(codeName) !== -1 &&
          item.codeIdentifier.toLowerCase().indexOf(codeIdentifier) !== -1;
    });
    this.handlePagination();
  }
  // 搜索状态皆为空,即调用重置函数
  if (codeName === '' && codeIdentifier === '') {
    this.handleReset();
  }
}

​ 重置,由于存在编辑,需要将搜索得到的部分数据 更新到 备份数据,后将备份数据给到 tableData,再次重新分页,回到第一页,并清空搜索 input 框。

// 搜索重置
handleReset() {
  this.searchButtonFlag = false;
  this.search.codeName = '';
  this.search.codeIdentifier = '';
  for (let i = 0, len = this.tableData.length; i < len; i++) {
    const numRow = this.tableData[i];
    // 这里的 codeSeqNum 相当于序号,每一行数据都有
    this.tableDataCopy[numRow.codeSeqNum - 1] = numRow;
  }
  this.tableData = JSON.parse(JSON.stringify(this.tableDataCopy));
  this.handlePagination();
}