Skip to content
Menu
CFC Studio
  • 实验室主页
  • CFC 招新简章
  • 友情链接
  • RSS订阅
CFC Studio

记一次傻逼的修改表格复选项的经历

Posted on 2019年11月5日2019年11月17日 by godlanbo

这天写项目,项目里面有个地方用表格呈现数据,虽然element-ui自己的表格组件自带滚动条,但是需要显示的数据有几十万,搞不定,翻页吧,每页多少多少。成了。

但是呢,这个表格有个批量操作的功能,用的组件自带的属性,只能对这个表格数据作用,也就是说我翻页了,刷新了这个组件当前绑定的数组,复选项就没了。这肯定不行嘛,翻页就忘了前几页的选项那不是没了。

所以现在这个情况就是需要记住以前选的对象,简单,搞个数组记录全部数据(以下统称allArr),然后本来本页数据就有个数组在记录选中的数据(以下统称nowArr),每次翻页的时候,allArr.concat(nowArr)一下,成了。然后是解决返回上一页的时候依旧高亮曾经选过的数据。这个稍微想了下(太菜了),那就在返回这一页的获取数据里写个匹配吧,循环这一页和全部数据,比对唯一标识,发现一样的就高亮它,并且加到nowArr(因为返回来这一页的这个数组清空了)。

for (let i = 0; i < this.tableData.length; i++) {
  for (let j = 0; j < this.allOutPutInfo.length; j++) {
    if (this.tableData[i].web_link === this.allOutPutInfo[j].web_link) {
      this.$refs.multipleTable.toggleRowSelection(this.tableData[i])
      this.nowArr[this.nowArr.length] = this.tableData[i]
    }
  }
}

恩,大概就是这样子。

因为用到了element-ui的组件,所以设置高亮状态的时候用的自带的方法 toggleRowSelection(),一开始也没注意,看到这个方法,看懂了就用了,保存之后本地测试就出问题了。

一开始点了几个复选项,翻页测试了一下,不错,有效果了,然后又试了试反复翻页,恩?怎么多翻几页高亮的选项就没了?立即开始console测试大法。

for (let i = 0; i < this.tableData.length; i++) {
  for (let j = 0; j < this.allOutPutInfo.length; j++) {
    if (this.tableData[i].web_link === this.allOutPutInfo[j].web_link) {
      this.$refs.multipleTable.toggleRowSelection(this.tableData[i])
      console.log(this.tableData[i]) // 1
      this.nowArr[this.nowArr.length] = this.tableData[i]
      console.log(this.nowArr)       // 2
    }
  }
}

于是发现诡异的事情,明明第一句打印出来是正常的,只是打印了匹配的对象,然而后面第二个打印出来nowArr却有重复的选项,长度也更长。?诡异,当时我是真的觉得诡异,同一个if语句里,出现了两种不同的运行结果。

后来把this.nowArr[this.nowArr.length] = this.tableData[i]这一句删了继续测试。。。第二个打印就正常了。。 。=。=??exm?

然后我突然想起table组件的一个事件 selection-change,这是原来控制本页复选项的事件。绑定的方法是这样的:

handleSelectionChange (val) {
  this.nowArr = val
},

每次当页的选项变动时,就把变动后的对象数组传给nowArr,因为一开始“选项变动”这个事件我不会用代码触发,所以这个方法我也还是写在那里的,就是当前页面选复选的时候用。然后。。toggleRowSelection(),这个组件自带的方法居然能触发组件的selection-change事件,我透,也就是说原来那样写就会触发这个方法自动添加一次已经被toggleRowSelection()标记为高亮的对象,然后我又手动添加了一次。。就重复了,重复之后多次匹配,把高亮状态反复翻转,所以就看到了,多翻几页,复选就没了的情况。

恩,保存,本地测试启动,恩?怎么翻几页又没了?我透哦。

检查了一下代码,发现了一个问题,在每次翻页的时候我都会添加一次这页所有选中的对象,然而,多次来回翻的时候,就会有重复的对象添加到allArr里面,然后在匹配的时候就会又重复翻转状态。

行,找到问题,就是每次在allArr那里去个重嘛。

然后我就用以前去重的经验写了对这个对象数组的去重,我知道以前不是写的对象数组,所以还特地改了点:

this.allOutPutInfo = this.nowArr.concat(this.allOutPutInfo).filter((value, index, arr) => {
  return JSON.stringify(arr).indexOf(JSON.stringify(value)) === JSON.stringify(arr).lastIndexOf(JSON.stringify(value))
})

恩,完美,我觉得没有问题了(以前就是这么去重的,成功了的),还特地用JSON.stringify把对象数组转成了字符串数组。但是在filter的运行过程中arr是不会改变的,所以这样写就把重复的全部去掉了,没有留下一个。又改:

this.allOutPutInfo = this.nowArr.concat(this.allOutPutInfo).filter((value, index, arr) => {
  return JSON.stringify(arr).indexOf(stringify(value)) === index
})

恩,如果匹配的到的value的位置不等于自己本身的位置,就去掉。看了看,应该没问题了。保存,测试。又没了。。

就很无语,不知道哪个地方出了毛病。。然后去查看JSON.stringify的解释,emm,自己傻逼了,这个函数对对象数组用并不能把对象变成JSON字符串,是应该用map对每一个对象这么用,我把这个函数套在数组外面。。人傻了:

this.allOutPutInfo = this.nowArr.concat(this.allOutPutInfo).filter((value, index, arr) => {
  return arr.map(value_ => JSON.stringify(value_)).indexOf(JSON.stringify(value)) === index
})

好了,最后终于搞定了,所有bug来自自己傻逼对函数认识的不到位。

2019/11/15 更新


看了评论加上自己又看了一下文档,重写了一下项目复选框的逻辑,现在变得更加简洁和高效了。

主要是两个事件的运用,element-ui里面table自带的:

事件 说明 参数
select 当用户手动勾选数据行的 Checkbox 时触发的事件 selection row
selection-all 当用户手动勾选全选 Checkbox 时触发的事件 selection

就是用这两个事件,可以将上面全部的代码整合为下面两个函数:

/*
*  <el-table
*    @select="handleSingleSelect"
*    @select-all="handleAllSelection">
*  </el-table>
*/
// 每当选取当页全部数据时触发
handleAllSelection (selection) {
  // 判断此次选取是选中还是取消(selection参数装的是此次选中数据构成的数组)
  if (selection.length !== 0) { // 若不为0,则此次选中为全部标记,加入allArr中
    // 用Set去重,考虑到Set不能对对象去重,做了点改变
    let set = new Set(this.allOutputInfo.concat(selection).map(value => JSON.stringify(value)))
    this.allOutputInfo = [...set].map(value => JSON.parse(value))
  } else {
    // 如果不是,那么就把本页所有的数据从allArr排除,因为此次是取消选中
    this.allOutputInfo = this.allOutputInfo.concat(this.tableData).filter((value, index, arr) => {
      // 这里直接indexOf对象翻页就不行了,翻页之后对同一个对象的引用不再一致
      let tempArr = arr.map(value_ => JSON.stringify(value_))
      let tempValue = JSON.stringify(value)
      // 如果前后判断位置不一样就剔除
      return tempArr.indexOf(tempValue) === tempArr.lastIndexOf(tempValue)
    })
  }
},
// 选中单个数据的时候
handleSingleSelect (selection, row) {
  // 首先判断这个数据是否已经在allArr中,如果在,此次操作就是取消标记,反之标记
  let theRowIndexInAllInfo = this.allOutputInfo.map(value => JSON.stringify(value)).indexOf(JSON.stringify(row))
  if (theRowIndexInAllInfo === -1) {
    // 不在直接添加就好了,这个方法可以免于去重
    this.allOutputInfo = this.allOutputInfo.concat(row)
  } else {
    // 直接删除对应位置的数据
    this.allOutputInfo.splice(theRowIndexInAllInfo, 1)
  }
}

这里在重新高亮本页数据的时候依然选择原来的双重循环方法,因为table没有方法是传入对象数组然后高亮里面全部对象的,只有单个高亮table数据的方法。

总结

在实现某个功能的时候多看看文档,以免漏掉一些重要的现成工具而导致实现功能的难度大增。

6 thoughts on “记一次傻逼的修改表格复选项的经历”

  1. ココロ说道:
    2019年11月10日 15:44

    记录选中的数据可以用 Set 来表示,这样就不会出现重复的情况

    output 是一个词,驼峰命名 allOutputInfo 这样更好


    vue 是数据驱动双向绑定的

    所以你可以
    用一个Array表示 当前页的原始数据 sourceData
    再用一个Set表示选中的 selectedData

    接下来你就可以写一个 computed 计算属性
    tableData() {
    // 根据 sourceData 和 selectedData 计算出提供给 table 的数据
    //(显示数据和是否选中)
    }
    然后tableData 传给 < el-table >

    每次选中或者取消选中某一个 row,你就用 Set 的 add , remove 方法,操作 selectedData

    当selectedData变化是,tableData会重新计算值,并重新render表格


    另外如果是写js ts的话,可以尝试使用 lodash,是个好东西

    回复
    1. godlanbo说道:
      2019年11月15日 17:08

      杨老板赏光,惶恐(雾),为什么会有去重这个说法,是我写的table事件选中的时候是直接返回一个选中对象的数组,所以都是直接concat到all里面,才有了concat的说法,看了杨老板的回复,又回去看了下element-ui的文档,发现table是有返回单个选中对象的事件的,只是当时没有仔细看。。
      杨老板牛逼=。=

      回复
      1. ココロ说道:
        2019年11月15日 18:14

        多写写,我会经常来看的😝

        回复
        1. godlanbo说道:
          2019年11月17日 12:08

          =。=ck

          回复
  2. ココロ说道:
    2019年11月10日 15:49

    另外,我推荐使用 React(逃

    回复
  3. kh说道:
    2019年11月14日 16:57

    不

    回复

发表评论 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

分类

  • CFC 周刊 (4)
  • CFC 技术 (29)
  • CFC 日常 (3)
  • 未分类 (15)
  • 活动通知 (3)

标签

ACM Android anime animeloop animeloop-cli APP Apple aria2 Array Blog CFC数据结构与算法训练指南 CoreData CQUT Don't Starve Hexo iBooks JavaScript macOS Matlab moeoverflow OpenCV Programming README RxJS SQLite SQLite3 Steam Swift Theme Web Xcode 主题模板 动漫 博客 反编译 妹子 循环 教程 数据库 游戏 算法 装逼 视频 重庆理工大学 饥荒

登录
©2023 CFC Studio | Powered by WordPress & Superb Themes