univer实现字段拖拽

2024-03-27  本文已影响0人  超人s

好久不写文章了,这篇是写给 Univer 群里的友友们看的。

1_1711617301 -big-original.gif

1. 获取canvas滚动偏移量

https://univer.work/zh-cn/guides/facade/general/#监听命令

通过监听命令api 可以知道canvas内滚动 会触发 命令sheet.operation.set-scroll

单独输出 命令sheet.operation.set-scroll 的params 可以获取到数据

代码:

      this.univerAPI.onBeforeCommandExecute((command) => {
        const { id, type, params } = command
          if (id === 'sheet.operation.set-scroll') {
            console.log('params', params)
            const { offsetX, offsetY, sheetId, sheetViewStartColumn, sheetViewStartRow, unitId } =
              params
            this.$emit('setScroll', {
              offsetX,
              offsetY,
              sheetId,
              sheetViewStartColumn,
              sheetViewStartRow,
              unitId
            })
          }
      })

image.png

{ offsetX, offsetY, sheetId, sheetViewStartColumn, sheetViewStartRow, unitId }

通过多次滚动,对数据的分析可以得出

这些数据为滚动后,左上角第一个格子的相关参数。

sheetViewStartColumn:左上角可视行的行数

sheetViewStartRow:左上角可视列的列数

offsetX:左上角可视第一个格被滚动的距离X

offsetY:左上角可视第一个格被滚动的距离Y

image.png

例如上图滚动后,则上面数据都是相对于B3格子。sheetViewStartColumn为B3的行,sheetViewStartRow为B3的列,offsetX为B3的x被遮住的部分,offsetY为B3的y被遮住的部分

同时,知道了sheetViewStartColumn,和sheetViewStartRow,就可以知道前面还有多少行多少列。就可以计算出前面所有行和列的距离。

2.获取鼠标位置

image.png

        <button @dragend="inserDataWithDrag" draggable="true">
          客户名称(可拖拽)
        </button>

下面就是全部核心代码 写满注释了。

前面几个常数在我的demo页面内,是上面图片的这样一个关系,可以根据自己的调整

/**
 * @description 拖拽字段到单元格内
 * @param {*} event
 */
const inserDataWithDrag = (event) => {
  const canvasLeft = 45 // 行数字宽度
  const pageLeft = 250 // 左侧字段区域宽带
  const canvasTop = 20 // 列字母高度
  const canvasTool = 32 // 工具条高度
  const canvasInput = 28 // 输入框高度
  const canvasCellLeft = canvasLeft + pageLeft
  const canvasCellTop = canvasTop + canvasTool + canvasInput
  const mouseX = event.clientX - canvasCellLeft // 鼠标在Excel表格内的相对位置
  const mouseY = event.clientY - canvasCellTop // 鼠标在Excel表格内的相对位置
  if (mouseX < 0 || mouseY < 0) return

  const allData = univerRef.value.getData() // 获取所有的sheet表 -
  const nowSheet = allData.sheets['sheet-01'] // 我暂时手动直接拿第一个表的内容了,需要的自己手动更换
  // Object.entries(allSheets).forEach(([key, value])
  const defaultColumnWidth = nowSheet.defaultColumnWidth // 默认行宽度
  const defaultRowHeight = nowSheet.defaultRowHeight // 默认列高度
  const rowData = nowSheet.rowData // 手动设置过列宽度的行数据
  const columnData = nowSheet.columnData // 手动设置过行高度的列数据
  let canvasScrollXHide = offsetX.value // 操作区间滚动后的偏移量x 滚动后 但滚动距离不超过1列 
  let canvasScrollYHide = offsetY.value // 操作区间滚动后的偏移量y 滚动后 但滚动距离不超过1行
  if (sheetViewStartColumn.value) { // 当页面滚动超过一行 
    const columnLen = new Array(sheetViewStartColumn.value).fill(null)
    const canvasScrollX = columnLen.reduce((acc, currentValue, currentIndex) => {
      if (columnData[currentIndex] && columnData[currentIndex].w) {
        // 如果手动设置过列宽
        return acc + columnData[currentIndex].w
      } else {
        return acc + defaultColumnWidth
      }
    }, 0)
    canvasScrollXHide += canvasScrollX // 拿到最终操作区间滚动后的全部偏移量x
  }
  if (sheetViewStartRow.value) { // 当页面滚动超过一列
    const rowLen = new Array(sheetViewStartRow.value).fill(null)
    const canvasScrollY = rowLen.reduce((acc, currentValue, currentIndex) => {
      if (rowData[currentIndex] && rowData[currentIndex].h) {
        // 如果手动设置过行高
        return acc + rowData[currentIndex].h
      } else {
        return acc + defaultRowHeight
      }
    }, 0)
    canvasScrollYHide += canvasScrollY // 拿到最终操作区间滚动后的全部偏移量y
  }

  // 拿到偏移量 就可以知道当前鼠标对于canvas的起点,0,0的位置
  const moseInCanvasX = canvasScrollXHide + mouseX // 得到鼠标相对于0,0位置的偏移量
  const moseInCanvasY = canvasScrollYHide + mouseY // 得到鼠标相对于0,0位置的偏移量

  console.log('鼠标位置:', mouseX, mouseY)
  console.log('鼠标在canvas内相对于起始0,0的位置:', moseInCanvasX, moseInCanvasY)

  // 计算鼠标在canvas内相对于起始0,0的位置在哪个单元格 获取行
  const getDragColumn = (moseInCanvasX, defaultColumnWidth) => {
    let count = 0
    let currentValue = 0

    while (currentValue <= moseInCanvasX) {
      if (columnData[count] && columnData[count].w) {
        // 如果下一列有设置过宽度 需要加上设置过的宽度
        currentValue += columnData[count].w
      } else {
        currentValue += defaultColumnWidth
      }
      count++
    }
    return count - 1 // 减去最后一次操作
  }

  // 计算鼠标在canvas内相对于起始0,0的位置在哪个单元格 获取列
  const getDragRow = (moseInCanvasY, defaultRowHeight) => {
    let count = 0
    let currentValue = 0

    while (currentValue <= moseInCanvasY) {
      if (rowData[count] && rowData[count].h) {
        // 如果下一行有设置过高度 需要加上设置过的高度
        currentValue += rowData[count].h
      } else {
        currentValue += defaultRowHeight
      }
      count++
    }
    return count - 1 // 减去最后一次操作
  }

  const column = getDragColumn(+moseInCanvasX, +defaultColumnWidth)
  const row = getDragRow(+moseInCanvasY, +defaultRowHeight)
  console.log('鼠标所在的位置列:', column)
  console.log('鼠标所在的位置行:', row)
}

已得到鼠标所在行列,赋值即可

在上面代码最后添加如下代码

  ...
  ...
  ...
  ...
  const column = getDragColumn(+moseInCanvasX, +defaultColumnWidth)
  const row = getDragRow(+moseInCanvasY, +defaultRowHeight)
  console.log('鼠标所在的位置列:', column)
  console.log('鼠标所在的位置行:', row)

  univerRef.value.setData({
    pos: [row, column, 1, 1],
    value: '{客户名称}' // 根据自身业务去赋值即可
  })

https://univer.work/zh-cn/guides/facade/sheet/#设置范围数据

上面univerRef.value.setData 是我封装过的赋值方法,本体也是官方api提供的

    setData({ pos, value }) {
      const [col, row, colNum, rowNum] = pos

      const activeSheet = this.univerAPI.getActiveWorkbook().getActiveSheet()

      const range = activeSheet.getRange(col, row, colNum, rowNum)
      range?.setValue(value)
    }

彩蛋:

最后如果想设置拖拽数据后单元格显示高亮:

image.png

https://univer.work/zh-cn/guides/facade/general/#监听命令

同样,通过监听命令api 可以知道canvas内被点击,会触发 命令sheet.operation.set-selections

参照最开的的调试输出params,最终结果是可以通过调用该命令高亮格子

      this.univerAPI.executeCommand('sheet.operation.set-selections', {
        selections: [{ range: { startRow: row, startColumn: column, endRow: row, endColumn: column } }]
      })

上一篇 下一篇

猜你喜欢

热点阅读