仿word可拖动行列改变单元格大小的table

<!DOCTYPE html PUBLIC "-//W4C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w4.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <META http-equiv=content-Type content="text/html; charset=utf-8">
    <style>
        #tbl {
            border-collapse: collapse;
        }

        #tbl td {
            border: 1px solid black;
        }

        .ui-selected {
            background: limegreen;
        }

    </style>

    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

</head>
<body>
<table ondragstart="return false;" onselectstart="return false;" id="tbl" cellspacing="1" cellpadding="5">
    <tr>
        <td>标题一</td>
        <td>标题二</td>
        <td>标题三</td>
        <td>标题四</td>
    </tr>
    <tr>
        <td>A</td>
        <td>B</td>
        <td>C</td>
        <td>D</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>T</td>
        <td>X</td>
        <td>Y</td>
        <td>U</td>
    </tr>
</table>


<script>
    //获取头部td集合
    var tblObj = document.getElementById("tbl");

    let t_row_num = tblObj.rows.length;
    for (let i = 0; i < t_row_num; i++) {
        //只有rows这个能选,col要先选rows,然后用cells

        let t_cell_num = tblObj.rows[i].cells.length;

        for (let j = 0; j < t_cell_num; j++) {
            let t_cell = tblObj.rows[i].cells[j];

            addListener(t_cell, "mousedown", on_td_mousedown);
            // addListener(t_cell, "mousemove", on_td_mousemove);
        }
    }

    let g_mousedown_resize_type = ''; //鼠标按下时的方向, 是 col,还是 row
    let g_mousedown_row_index   = ''; //鼠标按下时的行号
    let g_mousedown_col_index   = ''; //鼠标按下时的列号

    var g_td_resizeable = false;
    var g_target_td;
    var screenYStart    = 0;
    var screenXStart    = 0;
    var g_td_height     = 0;
    var g_td_width      = 0;
    var headerHeight    = 0;

    function on_td_mousedown(event) {
        if (!g_td_resizeable) {
            return;
        }

        var evt = event || window.event;

        // g_mousedown = true;

        let t_src_obj = getTarget(evt);

        console.log('on_td_mousemove t_src_obj');
        console.log(t_src_obj);
        console.log('cellIndex=' + t_src_obj.cellIndex);


        let t_cursor = t_src_obj.style.cursor;

        console.log('t_cursor=' + t_cursor);

        g_mousedown_resize_type = '';
        if ('col-resize' == t_cursor) {
            g_mousedown_resize_type = 'col-resize';
        } else {
            g_mousedown_resize_type = 'row-resize';
        }

        screenYStart = evt.screenY;
        screenXStart = evt.screenX;

        if (g_target_td) {
            g_td_height = g_target_td.offsetHeight;
            g_td_width  = g_target_td.offsetWidth;
        }

        headerHeight = tblObj.offsetHeight;
    }


    document.onmouseup = function (event) {
        tartgetTd                  = null;
        coltargetTd                = null;
        g_td_resizeable            = false;
        // g_mousedown                = false;
        colmousedown               = false;
        colresizeable              = false;
        g_mousedown_resize_type    = '';
        document.body.style.cursor = 'default';
    }

    document.onmousemove = function (event) {
        var evt       = event || window.event;
        var t_src_obj = getTarget(evt);

        console.log('on_td_mousemove t_src_obj');
        console.log(t_src_obj);

        let t_row_index = t_src_obj.parentNode.rowIndex;
        let t_col_index = t_src_obj.cellIndex;

        console.log('rowIndex=' + t_row_index);
        console.log('cellIndex=' + t_col_index);

        let t_cursor = t_src_obj.style.cursor;

        console.log('t_cursor=' + t_cursor);

        //rowIndex是未定义!!!cellIndex是好用的。我应该获取的是tr的rowindex
        //获取偏移 这里是鼠标的偏移

        var offsetY = evt.offsetY;
        var offsetX = evt.offsetX;
        console.log('offsetY=' + offsetY);

        if (g_mousedown_resize_type) {
            if (!g_target_td) {
                console.log('g_target_td 为空');
            } else if ('col-resize' == g_mousedown_resize_type) {
                let t_width = (g_td_width + (evt.screenX - screenXStart)) + "px";   //计算后的新的宽度

                g_target_td.style.width = t_width;

                let t_row_num = tblObj.rows.length;
                for (let i = 0; i < t_row_num; i++) {
                    //对每一行的单元格都要修改宽度
                    let t_cell         = tblObj.rows[i].cells[g_mousedown_col_index];
                    t_cell.style.width = t_width;
                }

            } else if ('row-resize' == g_mousedown_resize_type) {
                let t_delta_y = (evt.screenY - screenYStart);
                let t_height  = (g_td_height + t_delta_y) + "px";   //计算后的新的宽度

                console.log('g_td_height=' + g_td_height + ', t_height=' + t_height)
                console.log('screenYStart=' + screenYStart + ', evt.screenY=' + evt.screenY + ', t_delta_y=' + t_delta_y);

                g_target_td.style.height = t_height;

                let t_col_num = tblObj.rows[0].cells.length;
                //对这一行的每一列的单元格都要修改高度
                for (let i = 0; i < t_col_num; i++) {
                    let t_cell = tblObj.rows[g_mousedown_row_index].cells[i];

                    t_cell.style.height = t_height;
                }

                tblObj.style.height = (headerHeight + (evt.screenY - screenYStart)) + "px";
            }

        } else {
            g_mousedown_row_index = t_row_index;
            g_mousedown_col_index = t_col_index;

            if (t_row_index >= 0 && t_src_obj.offsetHeight - evt.offsetY <= 8) {
                //在单元格内部靠近底部框,实际改变本单元格
                console.log('在单元格内部靠近底部框,实际改变本单元格');

                g_target_td            = t_src_obj;
                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'row-resize';//修改光标样式
            } else if (t_src_obj.offsetWidth - evt.offsetX <= 8) {
                console.log('右边!!!!');

                //靠近单元格右边边框时,实际改变本单元格
                g_target_td            = t_src_obj;
                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'col-resize';//修改光标样式
            } else if (t_row_index > 0 && evt.offsetY <= 8) {
                console.log('在单元格内部靠近顶部框,实际改变上一行的单元格');
                g_mousedown_row_index = t_src_obj.parentNode.rowIndex - 1;
                let targetTr          = tblObj.rows[g_mousedown_row_index];
                if (targetTr) {
                    g_target_td = targetTr.cells[t_src_obj.cellIndex];
                }

                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'row-resize';
            } else if (t_col_index > 0 && evt.offsetX <= 8) {
                console.log('左边!!!!');
                console.log('t_row_index=' + t_row_index);

                let targetTr = tblObj.rows[t_row_index];
                if (targetTr) {
                    g_mousedown_col_index = t_col_index == 0 ? 0 : t_col_index - 1;
                    g_target_td           = targetTr.cells[g_mousedown_col_index];
                } else {
                    console.log('targetTr为空==========');
                }

                // console.log('g_mousedown_col_index=='+g_mousedown_col_index);
                // console.log('g_target_td==');
                // console.log(g_target_td);

                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'col-resize';
            } else {
                g_mousedown_resize_type = '';
                g_td_resizeable         = false;
                t_src_obj.style.cursor  = 'default';
            }
        }
    }

    function getTarget(evt) {
        return evt.target || evt.srcElement;
    }

    function addListener(element, type, listener, useCapture) {
        //这是两种写法,对应不同浏览器
        element.addEventListener ? element.addEventListener(type, listener, useCapture) : element.attachEvent("on" + type, listener);
    }

    $(function () {
        $('#tbl td').click(function () {
            if ($(this).hasClass("ui-selected")) {
                $('.ui-selected').removeClass('ui-selected');
            } else {
                $('.ui-selected').removeClass('ui-selected');
                $(this).addClass('ui-selected');
            }
        });
    });

</script>

</body>
</html>

 

 

合并单元格的拖动: 

<!DOCTYPE html PUBLIC "-//W4C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w4.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <META http-equiv=content-Type content="text/html; charset=utf-8">
    <style>
        #tbl {
            border-collapse: collapse;
        }

        #tbl td {
            border: 1px solid black;
        }

        .ui-selected {
            background: limegreen;
        }

    </style>

    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

</head>
<body>
<button onclick="show_table()">显示表格内容</button>
<table id="tbl" cellspacing="1" cellpadding="5">
    <tr>
        <td colspan="3" >标题一</td>
        <!--<td>标题二</td>-->
        <!--<td>标题二</td>-->
        <!--<td>标题三</td>-->
        <td>标题四</td>
    </tr>
    <tr>
        <td>A</td>
        <td>B</td>
        <td>C</td>
        <td>D</td>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>A</td>
        <!--<td>X</td>-->
        <td>X</td>
        <td>X</td>
        <td>U</td>
    </tr>
</table>
 

<script>
    //获取头部td集合
    var tblObj = document.getElementById("tbl");

    let t_row_num = tblObj.rows.length;
    for (let i = 0; i < t_row_num; i++) {
        //只有rows这个能选,col要先选rows,然后用cells

        let t_cell_num = tblObj.rows[i].cells.length;

        for (let j = 0; j < t_cell_num; j++) {
            let t_cell = tblObj.rows[i].cells[j];

            addListener(t_cell, "mousedown", on_td_mousedown);
            // addListener(t_cell, "mousemove", on_td_mousemove);
        }
    }

    let g_mousedown_resize_type = ''; //鼠标按下时的方向, 是 col,还是 row
    let g_mousedown_row_index   = ''; //鼠标按下时的行号
    let g_mousedown_col_index   = ''; //鼠标按下时的列号

    var g_td_resizeable = false;
    var g_target_td;
    var screenYStart    = 0;
    var screenXStart    = 0;
    var g_td_height     = 0;
    var g_td_width      = 0;
    var headerHeight    = 0;

    let g_arr_real_td = [];

    $(function () {
        g_arr_real_td = checkRealTd();
    })

    //检查Td是否真实存在,真实存在的是1,虚拟的td,即被跨行、跨列干掉的单元格的是0
    function checkRealTd() {
        var tblObj = document.getElementById("tbl");

        let t_row_num      = tblObj.rows.length;
        let t_max_cell_num = 0;

        for (let i = 0; i < t_row_num; i++) {
            //只有rows这个能选,col要先选rows,然后用cells

            let t_cell_num = tblObj.rows[i].cells.length;

            if (t_cell_num > t_max_cell_num) {
                t_max_cell_num = t_cell_num;
            }
        }

        let arr_real_td = [];

        //先初始化
        for (let i = 0; i < t_row_num; i++) {
            arr_real_td[i] = [];
            for (let j = 0; j < t_max_cell_num; j++) {
                arr_real_td[i][j] = 1;
            }
        }

        for (let i = 0; i < t_row_num; i++) {
            let t_row = tblObj.rows[i];
            console.log('i=' + i);

            for (let j = 0; j < t_max_cell_num; j++) {

                //找到这一行开头有多少个虚拟的td
                let t_v_td_num = 0;
                for (let v = 0; v < j; v++) {
                    if (0 == arr_real_td[i][v]) {
                        t_v_td_num++;
                    }
                }

                let t_real_j = j - t_v_td_num;
                let t_cell   = t_row.cells[t_real_j];
                console.log('j=' + j + ', t_v_td_num=' + t_v_td_num);
                if (!t_cell) {
                    console.log('元素不存在 ');
                    continue;
                }

                if (0 == arr_real_td[i][j]) {
                    continue;
                }

                let t_rowSpan = t_cell.rowSpan;
                let t_colSpan = t_cell.colSpan;

                if (1 == t_rowSpan && 1 == t_colSpan) {
                    continue;
                }

                console.log(' t_rowSpan=' + t_rowSpan + ', t_colSpan=' + t_colSpan);

                for (let rs = 0; rs < t_rowSpan; rs++) {
                    for (let cs = 0; cs < t_colSpan; cs++) {
                        arr_real_td[i + rs][t_real_j + cs] = 0;
                    }
                }

                arr_real_td[i][t_real_j] = 1;
            }
        }

        console.log('t_row_num=' + t_row_num + ', t_max_cell_num=' + t_max_cell_num);
        console.log('arr_real_td==');
        console.log(arr_real_td);

        return arr_real_td;

    }

    function show_table() {
        console.log(tblObj);

        console.log('rows===');
        console.log(tblObj.rows);

        console.log('cells===');
        for (let i in tblObj.rows) {
            console.log(tblObj.rows[i].cells);
        }

        checkRealTd();
    }

    function on_td_mousedown(event) {
        if (!g_td_resizeable) {
            return;
        }

        var evt = event || window.event;

        // g_mousedown = true;

        let t_src_obj = getTarget(evt);

        console.log('on_td_mousemove t_src_obj');
        console.log(t_src_obj);
        console.log('cellIndex=' + t_src_obj.cellIndex);


        let t_cursor = t_src_obj.style.cursor;

        console.log('t_cursor=' + t_cursor);

        g_mousedown_resize_type = '';
        if ('col-resize' == t_cursor) {
            g_mousedown_resize_type = 'col-resize';
        } else {
            g_mousedown_resize_type = 'row-resize';
        }

        screenYStart = evt.screenY;
        screenXStart = evt.screenX;

        if (g_target_td) {
            g_td_height = g_target_td.offsetHeight;
            g_td_width  = g_target_td.offsetWidth;
        }

        headerHeight = tblObj.offsetHeight;
    }


    document.onmouseup = function (event) {
        tartgetTd                  = null;
        coltargetTd                = null;
        g_td_resizeable            = false;
        // g_mousedown                = false;
        colmousedown               = false;
        colresizeable              = false;
        g_mousedown_resize_type    = '';
        document.body.style.cursor = 'default';
    }

    document.onmousemove = function (event) {
        var evt       = event || window.event;
        var t_src_obj = getTarget(evt);

        // console.log('on_td_mousemove t_src_obj');
        // console.log(t_src_obj);

        let t_row_index = t_src_obj.parentNode.rowIndex;
        let t_col_index = t_src_obj.cellIndex;

        // console.log('rowIndex=' + t_row_index);
        //  console.log('cellIndex=' + t_col_index);

        let t_cursor = t_src_obj.style.cursor;

        // console.log('t_cursor=' + t_cursor);

        //rowIndex是未定义!!!cellIndex是好用的。我应该获取的是tr的rowindex
        //获取偏移 这里是鼠标的偏移

        var offsetY = evt.offsetY;
        var offsetX = evt.offsetX;
        // console.log('offsetY=' + offsetY);

        if (g_mousedown_resize_type) {
            if (!g_target_td) {
                // console.log('g_target_td 为空');
            } else if ('col-resize' == g_mousedown_resize_type) {
                console.log('rowIndex=' + t_row_index);
                console.log('cellIndex=' + t_col_index);

                let t_width = (g_td_width + (evt.screenX - screenXStart)) + "px";   //计算后的新的宽度

                g_target_td.style.width = t_width;

                let t_col_span = g_target_td.colSpan;
                let t_row_span = g_target_td.rowSpan;

                console.log('t_col_span=' + t_col_span);
                let t_row_num = tblObj.rows.length;

                if (t_col_span > 1) {
                    //当这个单元格是合并单元格时,只改自己的宽度
                    let t_cell = tblObj.rows[t_row_index].cells[t_col_index];
                    if (t_cell) {
                        t_cell.style.width = t_width;
                    }
                } else {
                    //对每一行的这个单元格都要修改宽度
                    for (let i = 0; i < t_row_num; i++) {
                        //虚拟td数量
                        let t_v_td_num = 0;
                        for (let ri = 0; ri < t_col_index; ri++) {
                            if (0 == g_arr_real_td[i][ri]) {
                                t_v_td_num++;
                            }
                        }

                        let t_real_col_index = t_v_td_num + t_col_index;
                        console.log('i=' + i + ', t_v_td_num=' + t_v_td_num);

                        if (0 == g_arr_real_td[i][t_real_col_index]) {
                            console.log('i=' + i + ', t_real_col_index=' + t_real_col_index + ', 是虚拟td');
                            continue;
                        }

                        //对每一行的这个单元格都要修改宽度
                        let t_cell = tblObj.rows[i].cells[t_real_col_index];
                        if (t_cell) {
                            t_cell.style.width = t_width;
                        }
                    }
                }


            } else if ('row-resize' == g_mousedown_resize_type) {
                let t_delta_y = (evt.screenY - screenYStart);
                let t_height  = (g_td_height + t_delta_y) + "px";   //计算后的新的宽度

                // console.log('g_td_height=' + g_td_height + ', t_height=' + t_height)
                // console.log('screenYStart=' + screenYStart + ', evt.screenY=' + evt.screenY + ', t_delta_y=' + t_delta_y);

                g_target_td.style.height = t_height;

                let t_col_num = tblObj.rows[0].cells.length;
                //对这一行的每一列的单元格都要修改高度

                let t_row_span = g_target_td.rowSpan;
                if (1 == t_row_span) {
                    for (let i = 0; i < t_col_num; i++) {
                        let t_cell = tblObj.rows[g_mousedown_row_index].cells[i];
                        if (t_cell) {
                            t_cell.style.height = t_height;
                        }
                    }
                }

                tblObj.style.height = (headerHeight + (evt.screenY - screenYStart)) + "px";
            }

        } else {
            g_mousedown_row_index = t_row_index;
            g_mousedown_col_index = t_col_index;

            if (t_row_index >= 0 && t_src_obj.offsetHeight - evt.offsetY <= 8) {
                //在单元格内部靠近底部框,实际改变本单元格
                // console.log('在单元格内部靠近底部框,实际改变本单元格');

                g_target_td            = t_src_obj;
                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'row-resize';//修改光标样式
            } else if (t_src_obj.offsetWidth - evt.offsetX <= 8) {
                // console.log('右边!!!!');

                //靠近单元格右边边框时,实际改变本单元格
                g_target_td            = t_src_obj;
                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'col-resize';//修改光标样式
            } else if (t_row_index > 0 && evt.offsetY <= 8) {
                // console.log('在单元格内部靠近顶部框,实际改变上一行的单元格');
                g_mousedown_row_index = t_src_obj.parentNode.rowIndex - 1;
                let targetTr          = tblObj.rows[g_mousedown_row_index];
                if (targetTr) {
                    g_target_td = targetTr.cells[t_src_obj.cellIndex];
                }

                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'row-resize';
            } else if (t_col_index > 0 && evt.offsetX <= 8) {
                // console.log('左边!!!!');
                // console.log('t_row_index=' + t_row_index);

                let targetTr = tblObj.rows[t_row_index];
                if (targetTr) {
                    g_mousedown_col_index = t_col_index == 0 ? 0 : t_col_index - 1;
                    g_target_td           = targetTr.cells[g_mousedown_col_index];
                } else {
                    // console.log('targetTr为空==========');
                }

                // console.log('g_mousedown_col_index==' + g_mousedown_col_index);
                // console.log('g_target_td==');
                // console.log(g_target_td);

                g_td_resizeable        = true;
                t_src_obj.style.cursor = 'col-resize';
            } else {
                g_mousedown_resize_type = '';
                g_td_resizeable         = false;
                t_src_obj.style.cursor  = 'default';
            }
        }
    }

    function getTarget(evt) {
        return evt.target || evt.srcElement;
    }

    function addListener(element, type, listener, useCapture) {
        //这是两种写法,对应不同浏览器
        element.addEventListener ? element.addEventListener(type, listener, useCapture) : element.attachEvent("on" + type, listener);
    }

    $(function () {
        $('#tbl td').click(function () {
            if ($(this).hasClass("ui-selected")) {
                $('.ui-selected').removeClass('ui-selected');
            } else {
                $('.ui-selected').removeClass('ui-selected');
                $(this).addClass('ui-selected');
            }
        });
    });

</script>

</body>
</html>

 

Guess you like

Origin blog.csdn.net/wuzuyu365/article/details/105905196