在vue表格设计组件中实现历史记录以及撤销和还原功能

原创  郑建华   2021-08-21   128人阅读  0 条评论

    最近写了一个表格设计组件,用户可以通过右侧的属性面板,设置表格行数,列数,调整单元格填充色、边框线颜色、文本颜色。还可以直接操作单元格,插入行列,删除行列,合并拆分单元格,清空内容以及样式。

image.png

image.png

    然而在这样一个复杂的操作过程中,很有可能存在一些误操作或者调整效果不满意,想要撤销设置的效果。针对一些简单的效果还好,再重新设置下就能到达撤销效果,那如果是无法手动撤销的效果,或者说撤销的步骤比较多,操作繁琐。这样用户体验感就下降了。所以,手动实现一个撤销、还原操作是非常有必要的。

    基本实现思路:

    1、准备一个储存历史记录的数组。

    2、记录当前状态数据的索引。

    3、初始打开时,将数据存入历史记录数组中,设置索引位置。

    4、每操作一步,先删除历史记录数组索引位置之后的数据,再向历史记录数组末尾添加一条数据,并设置索引位置为数组最后一个元素。

    5、当前历史记录数组长度到底一定值,删除数组第一个元素保证长度不超过指定值。

    6、执行撤销操作时,将索引位置向前移动,再取出数据,进行表格渲染(业务操作)。

    7、执行还原操作是,将索引位置向后移动,再取出数据,进行表格渲染(业务操作)。


     难点以及解决方式:

    1、何时触发添加历史记录操作?

        当表格数据发生变化时触发,且不是由撤销、还原操作引发的数据变化时

    2、如何实现短时间内的操作视作一步变化?

        记录历史记录数据时,额外增加时间毫秒数,当下一次触发变化时,如果当前时间与最后一次记录时间间隔过短,则直接覆盖最后一条历史记录

    3、如何实现快捷键监听?

        使用widow.document.addEventListener添加事件监听,监听keydown事件,需要注意的是,一定要在销毁组件时删除事件监听,否则会出现多次调用。

    

代码:

data(){
    tableJsonOperateArray: [], // 表格json操作数组 用作表格操作历史记录
    operateIndex: -1, // 操作记录索引 用于标识在历史记录中的索引
    operateHistoryDataFlag: false, // 操作历史记录数据标志
},
method(){
// 表格json对象变化 触发
tableJsonChange({ oldTableJsonObj, newTableJsonObj }) {
  // 如果操作历史记录标志为true则不进行后续操作
  if (this.operateHistoryDataFlag) {
    return
  }
  // 操作记录索引不等于数组的最后一个下标  需要销毁该索引之后的记录
  if (this.operateIndex !== this.tableJsonOperateArray.length - 1) {
    // 删除的索引   操作记录索引+1
    const deleteIndex = this.operateIndex + 1
    // 删除的长度   总长度 - (索引下标+1)
    const deleteLen = this.tableJsonOperateArray.length - (this.operateIndex + 1)
    // 销毁当前索引之后的历史记录
    this.tableJsonOperateArray.splice(deleteIndex, deleteLen)
  }
  const curDate = new Date()
  // 操作记录数据
  const operateData = {
    historyTime: curDate.getTime(), // 历史记录时间毫秒数
    historyTimeFormat: this.$date.formatDate(curDate, 'yyyy-MM-dd hh:mm:ss'), // 历史记录时间格式化
    preSecond: 0, // 距离上一次历史记录间隔秒数
    tableJson: JSON.stringify(newTableJsonObj) // 表格json字符串
  }
  // 取数组最后一条数据
  const lastData = this.tableJsonOperateArray.length > 0 ? this.tableJsonOperateArray[this.tableJsonOperateArray.length - 1] : null
  // 获取历史记录时间毫秒数
  const historyTime = lastData ? lastData.historyTime : 0
  // 获取当前时间毫秒数
  const curDateTime = new Date().getTime()
  // 相差秒数
  const subSecond = (curDateTime - historyTime) / 1000
  // 设置间隔秒数
  operateData.preSecond = subSecond
  // 超过1秒
  if (subSecond > 1) {
    // 向后插入数据
    this.tableJsonOperateArray.push(operateData)
  // 不足1秒
  } else {
    // 更新最后一条数据
    this.$set(this.tableJsonOperateArray, this.tableJsonOperateArray.length - 1, operateData)
  }
  // 如果长度 大于50
  if (this.tableJsonOperateArray.length > 50) {
    // 删除第一个元素
    this.tableJsonOperateArray.shift()
  }
  // 设置操作记录索引为数组最后一个下标
  this.operateIndex = this.tableJsonOperateArray.length - 1
},
// 操作历史记录 operateType 操作类型  撤销(repeal) 或者 还原(restore)
operateHistory(operateType) {
  // 操作历史记录必须保证 历史记录数组有数据
  if (!this.tableJsonOperateArray.length) {
    // 无数据直接返回
    return
  }
  // 撤销操作且当前历史记录索引等于0
  // 或者 还原操作且当前列数记录索引等于最后一位
  if ((operateType === 'repeal' && this.operateIndex === 0) ||
      (operateType === 'restore' && this.operateIndex === this.tableJsonOperateArray.length - 1)) {
    // 返回
    return
  }
  // 开启操作历史记录标志
  this.operateHistoryDataFlag = true
  // 撤销
  if (operateType === 'repeal') {
    // 操作索引前移
    this.operateIndex--
  // 还原
  } else if (operateType === 'restore') {
    // 操作索引后移
    this.operateIndex++
  }
  // 取出历史记录数据
  const historyData = this.tableJsonOperateArray[this.operateIndex]
  // 获取表格json数据
  const tableJson = historyData.tableJson
  // 转换tableJson对象
  const tableJsonObj = JSON.parse(tableJson)
  this.$refs.tableProperties.tableProperty = JSON.parse(JSON.stringify(this.tableOptions))
  this.$refs.tableProperties.tablePropertyCopy = JSON.parse(JSON.stringify(this.tableOptions))
  // 刷新表格
  this.getTableRef().refreshTable(tableJson)
  // 获取表格配置信息
  this.tableOptions = tableJsonObj.options
  // 获取表格扩展属性值
  const extendOptions = tableJsonObj.extendOptions
  // 获取预览主题色编码
  const previewThemeColorCode = extendOptions ? extendOptions.previewThemeColorCode : ''
  // 预览主题色不为空
  if (previewThemeColorCode) {
    // 触发修改主题色方法
    this.$EventBus.$emit('updatePreviewThemeColorCode', previewThemeColorCode)
  }
  // 触发修改配置模式方法
  this.$EventBus.$emit('configModeChange', this.tableOptions.configMode)
  // 刷新业务数据
  this.$EventBus.$emit('refreshServiceData', {
    data: tableJsonObj.data
  })
  this.$forceUpdate()
  setTimeout(() => {
    this.operateHistoryDataFlag = false
  }, 0)
},
keydownFun(event) {
  // 撤销方法 当前为编辑模式
  if (event.ctrlKey && event.keyCode === 90 && !this.showPreview) {
    this.$nextTick(() => {
      this.$refs.generalTableDesignRef.operateHistory('repeal')
    })
    event.preventDefault()
    // 还原方法 当前为编辑模式
  } else if (event.ctrlKey && event.keyCode === 89 && !this.showPreview) {
    this.$nextTick(() => {
      this.$refs.generalTableDesignRef.operateHistory('restore')
    })
    event.preventDefault()
  }
}
},
mounted() {
// 监听键盘事件
window.document.addEventListener('keydown', this.keydownFun, false)
},
destroyed() {
  window.document.removeEventListener('keydown', this.keydownFun)
}



本文地址:https://www.zjh336.cn/?id=2056
版权声明:本文为原创文章,版权归 郑建华 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?