好久不写文章了,这篇是写给 Univer 群里的友友们看的。
1. 获取canvas滚动偏移量
通过监听命令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
})
}
})
{ offsetX, offsetY, sheetId, sheetViewStartColumn, sheetViewStartRow, unitId }
通过多次滚动,对数据的分析可以得出
这些数据为滚动后,左上角第一个格子的相关参数。
sheetViewStartColumn:左上角可视行的行数
sheetViewStartRow:左上角可视列的列数
offsetX:左上角可视第一个格被滚动的距离X
offsetY:左上角可视第一个格被滚动的距离Y
例如上图滚动后,则上面数据都是相对于B3格子。sheetViewStartColumn为B3的行,sheetViewStartRow为B3的列,offsetX为B3的x被遮住的部分,offsetY为B3的y被遮住的部分
同时,知道了sheetViewStartColumn,和sheetViewStartRow,就可以知道前面还有多少行多少列。就可以计算出前面所有行和列的距离。
2.获取鼠标位置
<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: '{客户名称}' // 根据自身业务去赋值即可
})
上面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)
}
彩蛋:
最后如果想设置拖拽数据后单元格显示高亮:
同样,通过监听命令api 可以知道canvas内被点击,会触发 命令sheet.operation.set-selections
参照最开的的调试输出params,最终结果是可以通过调用该命令高亮格子
this.univerAPI.executeCommand('sheet.operation.set-selections', {
selections: [{ range: { startRow: row, startColumn: column, endRow: row, endColumn: column } }]
})