vue实现表格选中效果,问题图片如下
合并单元格选中会出错,感兴趣的可以实现下
<template>
<el-affix position="top" :offset="0">
<div w-w="full" w-h="20" style="display: flex;background: white">
<el-space size="large">
<div>
<SvgIcon name="save" title="合并单元格" @click="setMerge"></SvgIcon>
</div>
</el-space>
</div>
</el-affix>
<table class="container" style="user-select: none;"
@mousedown="startSelection"
@mousemove="updateSelection"
@mouseup="endSelection">
<tr>
<td></td>
<td v-for="(item,index) in data[0]" :key="index" align="center" style="background-color: #f5f7f9;position: relative">
{{ word[index] + (index + 1) }}
</td>
</tr>
<tr v-for="(row, ri) in data" style="position: relative" >
<td style="min-width: 40px; background-color: #f5f7f9;" align="center" :value="false" >
{{ ri + 1 }}
</td>
<!-- :row="`${word[ci + Number(data[ri][ci].merge.colSpan > 1 ? data[ri][ci].merge.colSpan : 0)]}${ri + 1}`"-->
<!-- -->
<template v-for="(col, ci) in row" >
<td :class="getCellClass(ri, ci)"
:col="`${ci + 1}`"
:row="`${ri + 1}`"
:rowspan="data[ri][ci].merge.rowSpan"
:colspan="data[ri][ci].merge.colSpan"
style="min-width: 100px; height: min(34px);"
>
</td>
</template>
</tr>
</table>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon.vue";
const isSelecting = ref(false) // 是否正在进行选中操作
const selectionStart = ref({row: -1, col: -1}) // 选中区域的起始单元格
const selectionEnd = ref({row: -1, col: -1}) // 选中区域的结束单元格
const rowIndex = ref(0);
const colIndex = ref(0);
const data = ref([])
const word = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
const tableData = ref([])
import {computed, ref} from "vue";
import {defaultTableData} from "@/request/defaultTableData.js";
const setMerge = () => {
let { startRow, endRow, startCol, endCol } = getRowCol();
// 更新数据结构以处理合并单元格
for (let i = startRow - 1; i < endRow; i++) {
for (let j = startCol - 1; j < endCol; j++) {
if (i !== startRow - 1 || j !== startCol - 1) {
// 清除合并单元格的数据
data.value[i][j] = null;
}
}
}
data.value[startRow - 1][startCol - 1].merge.rowSpan = endRow - startRow + 1;
data.value[startRow - 1][startCol - 1].merge.colSpan = endCol - startCol + 1;
// 调整表格结构,移除多余的单元格
adjustTableStructure();
}
// 调整表格结构的函数
const adjustTableStructure = () => {
// 从数据数组中移除多余的单元格
data.value = data.value.map((row) => row.filter((cell) => cell !== null));
};
const createTable = () => {
tableData.value = defaultTableData
data.value = tableData.value[0].data
console.log(data.value)
}
createTable()
function startSelection(event) {
console.log(event.target)
if (event.target.getAttribute("value") === "false") return
// 开始选中操作
isSelecting.value = true;
activeCol.value = 0
activeRow.value = 0
selectionStart.value = getCellIndex(event.target);
console.log(selectionStart.value)
selectionEnd.value = {...selectionStart.value};
}
let debounceTimer = null;
function updateSelection(event) {
if (isSelecting.value) {
// 清除之前的计时器
if (debounceTimer !== null) {
clearTimeout(debounceTimer);
}
// 创建一个新的计时器,延迟执行 updateSelection
debounceTimer = setTimeout(() => {
activeCol.value = 0
activeRow.value = 0
selectionEnd.value = getCellIndex(event.target);
console.log(selectionEnd.value);
}, 1); // 在这里设置你希望的延迟时间(毫秒)
}
}
function endSelection() {
// 结束选中操作
isSelecting.value = false;
console.log(data.value)
console.log(selectionStart.value)
console.log(selectionEnd.value)
console.log(activeRow.value, activeCol.value)
}
const activeRow = ref(0)
const activeCol = ref(0)
function getCellIndex(target) {
// 根据单元格元素获取其在表格中的索引
const cell = target.closest("td");
if (cell) {
const row = cell.parentElement;
// 获取tr
console.log(cell.parentElement)
// console.log(row.parentElement.children)
let colspan = 0
let rowspan = 0
const colComputed = Array.from(row.parentElement.children).indexOf(row)
const rowComputed = Math.ceil(Array.from(row.children).indexOf(cell))
console.log(colComputed,rowComputed)
console.log(data.value[colComputed-1][rowComputed-1])
const {merge} = data.value[colComputed-1][rowComputed-1]
const {colSpan,rowSpan} = merge
if (colSpan > 1){
activeCol.value = colSpan - 1
}
if (rowSpan > 1){
activeRow.value = rowSpan - 1
}
return {
row: (colComputed < 1 ? 1 : colComputed),
col: (rowComputed < 1 ? 1 : rowComputed),
};
}
return {row: 1, col: 1};
}
const getCellClass = computed(() => {
// 根据选中区域的起始和结束单元格计算类名
const {startRow, endRow, startCol, endCol} = getRowCol()
// console.log(startRow, endRow, startCol, endCol)
return (rowIndex, colIndex) => {
// console.log(rowIndex, colIndex)
const classes = [];
if (rowIndex === startRow - 1 && colIndex >= startCol - 1 && colIndex <= endCol - 1) {
classes.push("border-top");
}
if (rowIndex === endRow - 1 && colIndex >= startCol - 1 && colIndex <= endCol - 1) {
classes.push("border-bottom");
}
if (colIndex === startCol - 1 && rowIndex >= startRow - 1 && rowIndex <= endRow - 1) {
classes.push("border-left");
}
if (colIndex === endCol - 1&& rowIndex >= startRow - 1 && rowIndex <= endRow - 1) {
classes.push("border-right");
}
if (rowIndex > startRow - 2 && rowIndex < endRow && colIndex > startCol - 2 && colIndex < endCol) {
classes.push("ch-td");
}
return classes.join(" ");
};
});
const getRowCol = () => {
const {row, col} = selectionStart.value;
const startRow = Math.min(row, selectionEnd.value.row);
const endRow = Math.max(row, selectionEnd.value.row);
const startCol = Math.min(col, selectionEnd.value.col);
const endCol = Math.max(col, selectionEnd.value.col);
return {startRow, endRow, startCol, endCol}
}
</script>
<style scoped>
>>> .el-affix .el-affix--fixed {
height: 24px;
}
table, tr, td, th {
border: 1px solid #c3cbdd;
font-size: 14px;
color: #606266;
}
.selected-cell {
background-color: lightblue; /* 自定义选中样式 */
}
.border-top {
border-top: #3a8ee6 2px solid;
}
.border-bottom {
border-bottom: #3a8ee6 2px solid;
}
.border-left {
border-left: #3a8ee6 2px solid;
}
.border-right {
border-right: #3a8ee6 2px solid;
}
.ch-td {
background-color: #d9d9d9;
}
</style>
【以下回答由 GPT 生成】
根据您提供的代码,您希望实现在Vue.js中选中Excel表格单元格的功能。这需要以下几步来实现:
data() {
return {
selectedCell: {}
}
},
methods: {
startSelection(event, rowIndex, columnIndex) {
// 确保点击的是单元格而不是其他元素
if (event.target.nodeName === 'TD') {
this.selectedCell.startRowIndex = rowIndex;
this.selectedCell.startColumnIndex = columnIndex;
}
},
// 其他方法
},
methods: {
startSelection(event, rowIndex, columnIndex) {
// 方法内容...
},
updateSelection(event, rowIndex, columnIndex) {
// 鼠标按下并移动时,更新结束位置坐标
if (this.selectedCell.startRowIndex !== undefined && this.selectedCell.startColumnIndex !== undefined) {
this.selectedCell.endRowIndex = rowIndex;
this.selectedCell.endColumnIndex = columnIndex;
}
},
// 其他方法
},
methods: {
startSelection(event, rowIndex, columnIndex) {
// 方法内容...
},
updateSelection(event, rowIndex, columnIndex) {
// 方法内容...
},
endSelection() {
// 清空选中的单元格数据
this.selectedCell = {};
},
// 其他方法
},
computed: {
isSelectedCell() {
return (rowIndex, columnIndex) => {
const startRowIndex = Math.min(this.selectedCell.startRowIndex, this.selectedCell.endRowIndex);
const endRowIndex = Math.max(this.selectedCell.startRowIndex, this.selectedCell.endRowIndex);
const startColumnIndex = Math.min(this.selectedCell.startColumnIndex, this.selectedCell.endColumnIndex);
const endColumnIndex = Math.max(this.selectedCell.startColumnIndex, this.selectedCell.endColumnIndex);
return rowIndex >= startRowIndex && rowIndex <= endRowIndex &&
columnIndex >= startColumnIndex && columnIndex <= endColumnIndex;
}
}
}
<td v-for="(item,index) in data[0]"
:key="index" align="center"
:class="{ 'selected': isSelectedCell(rowIndex, index) }"
style="background-color: #f5f7f9;position: relative">
{{ word[index] + (index + 1) }}
</td>
请注意,上述代码只是一个基本示例,您可能需要根据实际情况对其进行调整。此外,您还需要添加一些逻辑以保存选中的单元格数据或执行合并等操作。希望对您有所帮助!
【相关推荐】