VUE3实现表格的批量框选批量修改

效果

<table class="precipitation-table">
    <thead>
        <tr>
            <th class="time-headerzero"> </th>
            <th class="time-headerone">{{ 1 }} </th>
            <th class="time-headerone" v-for="n in 9" :key="n">{{ n+1 }}</th>
        </tr>
    </thead>
    <tbody>
        <tr v-for="(group, groupIndex) in groupedRainMinuteKeys" :key="groupIndex">
            <td class="time-column">{{ `${groupIndex + '1'}-${groupIndex * 10 +
                10}min` }}</td>
            <td v-for="(min, index) in group" :key="index"
                @mousedown="startSelect(groupIndex, index)"
                @mousemove="selectCells(groupIndex, index)" 
                @mouseup="endSelect"
                :class="{ 'selected-cell': selectedCells.has(`${groupIndex}-${index}`) }">
                <el-input v-number class="table_value-input "
                 size="small"
                 @input="val => applyBatchValue(val)"
                 v-model="form.rainMinuteMap[min].v"
                 placeholder="-"></el-input>
            </td>
        </tr>
    </tbody>
</table>

 行列动态生成​​:


表头通过v-for="n in 9"循环生成1-10列的标题;表体通过groupedRainMinuteKeys分组数据动态渲染行,每行对应一个时间段(如"1-10min"),单元格内嵌套el-input输入框。

表头通过v-for="n in 9"循环生成1-10列的标题;

  <thead>
        <tr>
            <th class="time-headerzero"> </th>
            <th class="time-headerone">{{ 1 }} </th>
            <th class="time-headerone" v-for="n in 9" :key="n">{{ n+1 }}</th>
        </tr>
    </thead>

 

要为每一个表格绑定对应的数据,他的数据元素一共有六十个

进行分组分批。把元素分为六组,一行一组进行渲染

/**
 * 计算属性:将 `rainMinuteKeys` 数组按每 10 个元素为一组进行分组。
 * 
 * 该函数通过遍历 `rainMinuteKeys` 数组,将其分割成多个子数组,每个子数组包含最多 10 个元素。
 * 最终返回一个包含这些子数组的数组。
 * 
 * @returns {Array<Array>} 返回一个二维数组,每个子数组包含最多 10 个元素。
 */
const groupedRainMinuteKeys = computed(() => {
    const result = [];
    
    // 遍历 `rainMinuteKeys` 数组,每 10 个元素为一组进行切片
    for (let i = 0; i < rainMinuteKeys.value.length; i += 10) {
这段代码的功能是将rainMinuteKeys.value数组从索引i开始,截取10个元素,并将这10个元素作为一个子数组推入result数组中。
        result.push(rainMinuteKeys.value.slice(i, i + 10));
    }
    
    return result;
});

 

 先生成分钟区间 groupindex是 0 1 2 3 4 5 

group是具体的 值

然后生成具体的表格内容 从

遍历

 

    <tbody>
        <tr v-for="(group, groupIndex) in groupedRainMinuteKeys" :key="groupIndex">
            <td class="time-column">{{ `${groupIndex + '1'}-${groupIndex * 10 +
                10}min` }}</td>
            <td v-for="(min, index) in group" :key="index"
                @mousedown="startSelect(groupIndex, index)"
                @mousemove="selectCells(groupIndex, index)" 
                @mouseup="endSelect"
                :class="{ 'selected-cell': selectedCells.has(`${groupIndex}-${index}`) }">
                <el-input v-number class="table_value-input "
                 size="small"
                 @input="val => applyBatchValue(val)"
                 v-model="form.rainMinuteMap[min].v"
                 placeholder="-"></el-input>
            </td>
        </tr>
    </tbody>

 

 ​​交互逻辑设计​

  • ​框选功能实现​​:
    • ​事件监听​​:通过@mousedown@mousemove@mouseup实现框选交互。
    • ​选区计算​​:selectCells函数根据起始和结束位置计算矩形选区,动态更新selectedCells集合中的单元格坐标(格式为groupIndex-index)。
    • ​状态管理​​:selectedCells通过Vue的ref管理选区状态,选中单元格通过:class="{ 'selected-cell': ... }高亮显示。
  • ​批量修改数值​​:
    输入框的@input事件触发applyBatchValue,遍历selectedCells集合,将当前输入值同步到所有选中单元格对应的数据字段。

 当鼠标按下时,会记录表格的行数据和列数据对应的索引传入方法中,去记录对应的值

/**
 * 开始框选操作,初始化框选状态并设置起始单元格。
 * 
 * @param {number} groupIndex - 单元格所在组的索引。
 * @param {number} index - 单元格在组内的索引。
 * @returns {void} 无返回值。
 */
function startSelect(groupIndex, index) {
    // 标记当前正在进行框选操作
    isSelecting.value = true;
    
    // 记录框选的起始单元格
    startCell = { groupIndex, index };
    
    // 清空已选中的单元格集合
    selectedCells.value.clear();
    
    // 将起始单元格添加到已选中的单元格集合中
    selectedCells.value.add(`${groupIndex}-${index}`);
}
/**
 * 在框选过程中,根据起始单元格和当前单元格的位置,计算并更新选中的单元格范围。
 * 
 * @param {number} groupIndex - 当前单元格的组索引。
 * @param {number} index - 当前单元格在组内的索引。
 * 
 * @returns {void} 该函数没有返回值,但会更新 `selectedCells` 集合。
 */
function selectCells(groupIndex, index) {
    // 如果当前未处于框选状态或没有起始单元格,则直接返回
    if (!isSelecting.value || !startCell) return;

    // 获取起始单元格的组索引和组内索引
    const { groupIndex: startGroupIndex, index: startIndex } = startCell;

    // 计算当前框选范围的组索引和组内索引的最小值和最大值
    const minGroupIndex = Math.min(startGroupIndex, groupIndex);
    const maxGroupIndex = Math.max(startGroupIndex, groupIndex);
    const minIndex = Math.min(startIndex, index);
    const maxIndex = Math.max(startIndex, index);

    // 清空当前选中的单元格集合
    selectedCells.value.clear();

    // 遍历框选范围内的所有单元格,并将其添加到选中的单元格集合中
    for (let i = minGroupIndex; i <= maxGroupIndex; i++) {
        for (let j = minIndex; j <= maxIndex; j++) {
            selectedCells.value.add(`${i}-${j}`);
        }
    }
}
/**
 * 结束框选操作
 * 该函数用于结束当前的框选状态,将框选标志设置为 false,并清空起始单元格的引用。
 * 无参数
 * 无返回值
 */
function endSelect() {
    // 结束框选状态
    isSelecting.value = false;
    // 清空起始单元格的引用
    startCell = null;
}

批量修改数值​​:


输入框的@input事件触发applyBatchValue,遍历selectedCells集合,将当前输入值同步到所有选中单元格对应的数据字段。

<!-- 
  el-input 组件用于输入框的渲染和交互。
  该输入框具有以下特性:
  - 使用 v-number 指令,限制输入内容为数字。
  - 应用了 table_value-input 样式类,用于自定义样式。
  - 设置 size 为 small,表示输入框的尺寸为小号。
  - 监听 input 事件,当输入内容发生变化时,调用 applyBatchValue 函数,并将当前输入值作为参数传递。
  - 使用 v-model 双向绑定 form.rainMinuteMap[min].v,将输入框的值与表单数据中的 rainMinuteMap[min].v 属性进行绑定。
  - 设置 placeholder 为 "-",表示输入框为空时的占位符。
-->
<el-input v-number class="table_value-input " 
          size="small" 
          @input="val => applyBatchValue(val)"   这段代码是Vue中的事件监听器,当输入框的值发生变化时,会触发applyBatchValue函数,并将当前输入值作为参数传递给该函数。
          v-model="form.rainMinuteMap[min].v" 
          placeholder="-">
</el-input>

高效批量操作​

  • ​框选多单元格​​:
    用户可通过鼠标拖拽选择连续区域的单元格,支持跨行跨列操作(如选择5-15min的第2-5列)。

  • ​一键批量赋值​​:
    选中区域后,在任意选中单元格输入数值,所有选中单元格自动同步更新,大幅提升数据录入效率。

 

/**
 * 批量修改选中的单元格的值
 * 
 * 该函数遍历所有选中的单元格,并根据传入的值 `val` 更新这些单元格的值。
 * 单元格的键值通过 `selectedCells` 获取,每个键值表示单元格在分组中的位置。
 * 函数会根据键值找到对应的 `rainMinuteMap` 中的条目,并将其值更新为 `val`。
 * 
 * @param {any} val - 要应用到选中单元格的新值
 */
function applyBatchValue(val) {
    // 遍历所有选中的单元格
    selectedCells.value.forEach(cellKey => {
        // 解析单元格键值,获取分组索引和单元格索引
        const [groupIndex, index] = cellKey.split('-').map(Number);
        
        // 获取对应分组中的最小分钟值
        const min = groupedRainMinuteKeys.value[groupIndex][index];
        
        // 更新 `rainMinuteMap` 中对应条目的值
        form.value.rainMinuteMap[min].v = val;
    });
}
.selected-cell {
    background-color: #93aeb9; /* 高亮选中单元格 */
}

在Vue中,冒号:v-bind的简写,用于动态绑定属性或类名。class前面的冒号表示class的值是一个表达式,而不是静态字符串。这里通过判断selectedCells集合是否包含当前单元格的索引,动态决定是否添加selected-cell类名。

在css中加入下面代码可以让他不选中文字

user-select:none;

加上之后就不会出现选中文字的情况了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值