鼠标滑动选中表格部分数据列(vue指令)

文章目录

代码

指令代码

js 复制代码
// 获得鼠标移动的范围
function getMoveRange(startClientX, endClientX, startClientY, endClientY) {
    const _startClientX = Math.min(startClientX, endClientX);
    const _endClientX = Math.max(startClientX, endClientX);
    const _startClientY = Math.min(startClientY, endClientY);
    const _endClientY = Math.max(startClientY, endClientY);
    // 判断鼠标移动的距离是否大于 10
    const moveX = _endClientX - _startClientX;
    const moveY = _endClientY - _startClientY;
    return {
        moveX,
        moveY,
    };
}

// 获得鼠标划过的行索引
function getRowRangeIndex(startRowIndex, endRowIndex) {
    const start = Math.min(startRowIndex, endRowIndex);
    const end = Math.max(startRowIndex, endRowIndex);
    return {
        start,
        end,
    };
}

const rangeselect = {
    async bind(el, binding, vnode) {
        const rangeDiv = document.createElement('div');
        rangeDiv.id = 'rangeSelectDiv';
        rangeDiv.style.display = 'none';
        rangeDiv.style.position = 'absolute';
        rangeDiv.style.pointerEvents = 'none';
        rangeDiv.style.zIndex = 9999;
        rangeDiv.style.backgroundColor = '#0088ff40';
        rangeDiv.style.top = 0;
        rangeDiv.style.left = 0;
        rangeDiv.style.border = '1px solid #0088ff';
        document.body.append(rangeDiv);
        let mousedown = false;
        let startRowIndex = -1;
        let endRowIndex = -1;
        let startClientX = 0; // 用于计算移动的距离
        let startClientY = 0; // 用于计算移动的距离
        let endClientX = 0; // 用于计算移动的距离
        let endClientY = 0; // 用于计算移动的距离
        const { componentInstance: $table } = await vnode;
        el.onmousedown = (event) => {
            const cell = event.target.closest('td');
            if (cell) {
                const elCheckboxElement = cell.querySelector('.el-checkbox');
                if (elCheckboxElement) {
                    event.preventDefault();
                    mousedown = true;
                    const rowIndex = cell.parentNode.rowIndex;
                    if (binding.value.handleMouseDown) {
                        binding.value.handleMouseDown(rowIndex);
                    }
                    startRowIndex = rowIndex;
                    endRowIndex = rowIndex;
                    startClientX = event.clientX;
                    startClientY = event.clientY;
                    endClientX = event.clientX;
                    endClientY = event.clientY;
                    rangeDiv.style.top = `${startClientY}px`;
                    rangeDiv.style.left = `${startClientX}px`;
                    rangeDiv.style.display = 'block';
                }
            }
        };
        el.onmousemove = (event) => {
            if (mousedown) {
                el.style.userSelect = 'none';
                event.preventDefault();
                endClientX = event.clientX;
                endClientY = event.clientY;
                const xDiff = endClientX - startClientX;
                const yDiff = endClientY - startClientY;
                rangeDiv.style.height = `${Math.abs(yDiff)}px`;
                rangeDiv.style.width = `${Math.abs(xDiff)}px`;
                if (xDiff >= 0 && yDiff >= 0) {
                    rangeDiv.style.transform = '';
                } else if (xDiff < 0 && yDiff < 0) {
                    rangeDiv.style.top = `${endClientY}px`;
                    rangeDiv.style.left = `${endClientX}px`;
                } else if (xDiff > 0 && yDiff < 0) {
                    rangeDiv.style.top = `${endClientY}px`;
                } else if (xDiff < 0 && yDiff > 0) {
                    rangeDiv.style.left = `${endClientX}px`;
                }
                const moveRange = getMoveRange(startClientX, endClientX, startClientY, endClientY);
                // 判断鼠标移动的距离是否大于 10
                if (moveRange.moveY > 10 && moveRange.moveX > 5 && startRowIndex > -1 && endRowIndex > -1) {
                    const cell = event.target.closest('td');
                    if (cell) {
                        const rowIndex = cell.parentNode.rowIndex;
                        endRowIndex = rowIndex;
                        const rowRangeIndex = getRowRangeIndex(startRowIndex, endRowIndex);
                        if (!event.ctrlKey) {
                            $table.clearSelection();
                        }
                        for (let i = rowRangeIndex.start; i <= rowRangeIndex.end; i++) {
                            if (binding.value.handleMousemove) {
                                binding.value.handleMousemove(i, true)
                            }
                        }
                    }
                }
            }
        };
        el.onmouseup = () => {
            mousedown = false;
            rangeDiv.style.height = '0px';
            rangeDiv.style.width = '0px';
            rangeDiv.style.top = '0px';
            rangeDiv.style.left = '0px';
            rangeDiv.style.display = 'none';
            startRowIndex = -1;
            endRowIndex = -1;
            el.style.userSelect = 'text';
        };
    },
};

使用代码

html 复制代码
<!-- vue-template -->
<el-table ref="tableRef" v-rangeselect="{handleMousemove}" :data="tableData" border stripe>
	<el-table-column type="selection" width="55"></el-table-column>
	<el-table-column label="序号" width="60"></el-table-column>
</el-table>
js 复制代码
// vue-script
{
	data() {
        return {
            tableData: [],
        }
    },
    directives: {
        rangeselect
    },
    methods: {
        handleMousemove(rowIndex, checked) {
            const table = this.$refs.tableRef;
            const tempTableData = this.tableData[rowIndex];
            table.toggleRowSelection(tempTableData, checked);
        },
    }
}
相关推荐
IT、木易几秒前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7206 分钟前
Ajax相关
前端·javascript·ajax
bin915324 分钟前
DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)
前端·javascript·vue.js·ecmascript·deepseek
那就可爱多一点点41 分钟前
超高清大图渲染性能优化实战:从页面卡死到流畅加载
前端·javascript·性能优化
飞天大河豚3 小时前
2025前端框架最新组件解析与实战技巧:Vue与React的革新之路
vue.js·react.js·前端框架
十步杀一人_千里不留行4 小时前
React Native 下拉选择组件首次点击失效问题的深入分析与解决
javascript·react native·react.js
customer085 小时前
【开源免费】基于SpringBoot+Vue.JS医疗报销系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
道不尽世间的沧桑5 小时前
第9篇:插槽(Slots)的使用
前端·javascript·vue.js
B站计算机毕业设计超人5 小时前
计算机毕业设计SpringBoot+Vue.jst房屋租赁系统(源码+LW文档+PPT+讲解)
vue.js·spring boot·后端·eclipse·intellij-idea·mybatis·课程设计
bin91535 小时前
DeepSeek 助力 Vue 开发:打造丝滑的滑块(Slider)
前端·javascript·vue.js·前端框架·ecmascript·deepseek