zoukankan      html  css  js  c++  java
  • 简易表格编辑器

    SMMS有个建表工具,尝试使用HTML模仿出一个简单的做为练习.

    截图:

     

    一.实现SMMS建表工具的操作

    1. 点击单元格,进入编辑状态.
    2. 按TAB切换单元格
    3. 按方向箭切换单元格
    4. 按空格设定取消主键列

    二.实现思路:

      1.DOM结构使用div(行)span(列) <div><span></span><span></span>...</div>

      2.每个span上设置tabindex=0,当获得焦点时,在其内生成表单元素.input select textarea等等.失去焦点时,将值取出来写到span内.

      3.给input设定onkeydown事件,方向键切换临近单元格

    三.实现过程中:

      在实现TAB时费了不少功夫,按tab时,总是不能按预想的那样移到前一个或者后一个列上.在向span中加入了表单元素后,就更加混乱.后来发现在每个span上tabindex=0这个属性,由于值一样,所以tab就按相临的去找.

      当span得到焦点后,会向其内生成一个表单元素.表单元素上绑定失去焦点事件blue和keydown事件.blue用于将表单元素的值取出,然后写到span中.这里有个细节就是,span得到焦点后,要将tabindex=-1,即按tab时,不能得到焦点.如果不这样做,那么span处于编辑状态后,按tab就移动不了.因为它会移动到span上,而span的得到焦点事件又是在其内生成表单.这样就形成一个死循环.所以当span得到焦点后,需要将tabindex=-1,然后在该 span内的表单元素的失去焦点事件上再tabindex=0.这样就实现了焦点顺序的正确.不会因为新生成了表单元素而乱(表单元素默认能获得焦点).

      按上下方向键盘切换到上下行的同列,这个较简单,取得当前事件span的列索引,然后找到上下行的同列span让它获得焦点.注意是否有上下行.

      按左右方向键切换到同行临近列.如果是输入状态的文本框则判断光标位置,如果在最左并且按左方向,则移动.同理按右方向键也一样.如果是select框,则直接移动到临近.取消默认行为.textarea没做此功能.

    四.主要代码 

    .field-table-box {
        border-top: 1px solid #ccc;
        border-left: 1px solid #ccc;
    }
    .field-rows{ 
        height:300px;
        overflow-y:auto;
    }
    .field-form-control {
        border: none;
        width: 100%;
        height: 100%;
        outline:none;/*用谷歌浏览器时:如果元素得到焦点.会默认有个蓝色边框.加这个可以去掉.(EDGE,FF没这问题)*/
    }
    
        .field-form-control:focus {
            background-color: #75e0f5;
            border:none;
        }
    
    .field-col-title, .field-col {
        display: inline-block;
        font-size: 14px;
        height: 24px;
        line-height: 24px;
        text-align: center;
        vertical-align: top;
        border-right: 1px solid #ccc;
        border-bottom: 1px solid #ccc;
        outline:none;
    }
    
    .field-col {
        color: #444;
    }
    .field-col.editinfo {
        height: 200px;
        line-height: 200px;
    }
        .field-col.pk {
            cursor: crosshair;
            color: orangered;
        }
    
        .field-col-title.pk, .field-col.pk {
            width: 40px;
        }
    
        .field-col-title.name, .field-col.name {
            width: 140px;
        }
    
        .field-col-title.type, .field-col.type {
            width: 140px;
        }
    
        .field-col-title.len, .field-col.len, .field-col-title.len2, .field-col.len2 {
            width: 60px;
        }
    
        .field-col-title.dval, .field-col.dval {
            width: 120px;
        }
    
        .field-col-title.info, .field-col.info {
            width: 180px;
        }
        .field-col.info{
    
        }
    .field-form-control.info {
        width: 100%;
    }
    
    .field-col-title.delrow, .field-col-title.moverow, .field-col-title.moverow, .field-col-title.insertrow {
        width: 40px;
    }
    
    .field-col.delrow, .field-col.moverow-down, .field-col.moverow-up, .field-col.insertrow {
        font-size: 0;
        width: 40px;
        cursor: pointer;
    }
    
        .field-col.delrow:hover, .field-col.moverow-down:hover, .field-col.moverow-up:hover, .field-col.insertrow:hover {
            font-size: 16px; 
            font-weight: 600;
        }
    
    .field-col.delrow {
        color: orangered;
    }
    .field-col.delrow:active{
          color: #fff;
            background-color: orangered;
    }
    .field-col.moverow-up, .field-col.moverow-down {
        color: #999;
    }
    
        .field-col.moverow-up:active {
            color: #fff;
            background-color: blue;
        }
    
        .field-col.moverow-down:active {
            color: #fff;
            background-color: green;
        }
    
    .field-col.insertrow {
        color: #4679ca;
    }
    
        .field-col.insertrow:active {
            color: #fff;
            background-color: #000;
        }
    样式
    <div class="field-table-box" id="field_table_box">
        <div class="field-table-cols">
            <h5 class="field-col-title pk">PK</h5>
            <h5 class="field-col-title name">列名</h5>
            <h5 class="field-col-title type">数据类型</h5>
            <h5 class="field-col-title len">长度</h5>
            <h5 class="field-col-title len2">精度</h5>
            <h5 class="field-col-title dval">默认值</h5>
            <h5 class="field-col-title info">列说明</h5>
            <h5 class="field-col-title moverow">上移</h5>
            <h5 class="field-col-title moverow">下移</h5>
            <h5 class="field-col-title insertrow">插行</h5>
            <h5 class="field-col-title delrow"></h5>
        </div>
    </div>
    
    <template id="tpl_fieldrow">
        <div class="fieldrow">
            <span class="field-col pk noselect" onclick="onClick_SetPk(this)" onkeyup="onkeyup_SetPk(event,this)" tabindex="0"></span>
            <span class="field-col name" onfocus="fieldCol_focus_toEdit(this)" tabindex="0"></span>
            <span class="field-col type" onfocus="fieldColType_toSelect(this)" tabindex="0" val="1">字符串</span>
            <span class="field-col len" onfocus="fieldCol_focus_toEdit(this)" tabindex="0">20</span>
            <span class="field-col len2" onfocus="fieldCol_focus_toEdit(this)" tabindex="0">2</span>
            <span class="field-col dval" onfocus="fieldCol_focus_toEdit(this)" tabindex="0">NULL</span>
            <span class="field-col info" onfocus="fieldCol_focus_info(this)" tabindex="0"></span>
            <span class="field-col moverow-up noselect" onclick="fieldColOp_click_moveRow(this)">&#9650;</span>
            <span class="field-col moverow-down noselect" onclick="fieldColOp_click_moveRow(this)">&#9660;</span>
            <span class="field-col insertrow noselect" onclick="fieldColOp_click_insertRow(this)">&#9768;</span>
            <span class="field-col delrow noselect" onclick="fieldCopOp_click_delRow(this)">&#10005;</span>
        </div>
    </template>
    <template id="tpl_fieldcol_type_select">
        <select class="field-form-control" onblur="fieldType_select_blur(this)" onkeydown="fieldType_select_keydown(event,this)">
            <option value="1">字符串</option>
            <option value="2">整数</option>
            <option value="3">小数</option>
            <option value="4">时间</option>
        </select>
    </template>
    html
    /*
    关于列的编辑功能模仿了SMMS工具的建表功能
    例如:
        点击某一个列名,它就会变成可编辑的,实现上是在点击后,套了一个INPUT框
    */
    $(function ()
    {
        refreshEditStatus();
    })
    // 编辑列之后刷新编辑区域状态
    function refreshEditStatus()
    {
        // 自动增加新的编辑行
        addRowTpl();
        // 说明textarea框或处于编辑时的放大状态,此处还原
        $('.field-col').removeClass('editinfo');
    }
    // 增加一行到制表工具中:如果没新行加入(列名为空视为有新行),否则不加入
    function addRowTpl()
    {
        var hasNewRow = false;
        $('#field_table_box').find('.field-col.name').each(function ()
        {
            if (String.IsNullOrWhiteSpace($(this).html()))
            {
                hasNewRow = true;
                return false;
            }
        })
        if (hasNewRow == false)
            $('#field_table_box').append($('#tpl_fieldrow').html());
    }
    // 主键列: 按空格时,按上下键时
    function onkeyup_SetPk(event, thisobj)
    {
        var e = event || window.event;
        //console.log(e.keyCode);
        if (e.keyCode == 32)
        {
            onClick_SetPk(thisobj);
            return;
        }
        // 当前编辑对象在fieldrow中的索引位置
        var colindex = $(thisobj).index();
        if (e.keyCode == 38)
        {
            // 上一行
            var prevrow = $(thisobj).parent('.fieldrow').prev();
            if (prevrow.length == 1)
            {
                prevrow.children().eq(colindex).focus();
            }
        } else if (e.keyCode == 39)
        {
            // 移向右一列 不考虑右侧无列情况
            $(thisobj).next().focus();
        }
        else if (e.keyCode == 40)
        {
            // 下一行
            var nextrow = $(thisobj).parent('.fieldrow').next();
            if (nextrow.length == 1)
            {
                nextrow.children().eq(colindex).focus();
            }
        }
    }
    // 切换设置 鼠标单击时切换
    function onClick_SetPk(thisobj)
    {
        if ($(thisobj).html() == '')
        {
            $('.field-col.pk').html('');
            $(thisobj).html('主键');
        } else
        {
            $('.field-col.pk').html('');
        }
        return;
    }
    // 列名称,长度,默认值: 获得焦点后,其内生成input
    function fieldCol_focus_toEdit(thisobj)
    {
        if ($(thisobj).find('input').length == 1)
            return;
        var html = '<input class="field-form-control" onblur="field_input_blur(this)" onkeydown="field_input_updownArrow(event,this)" type="text"  />';
        var val = $(thisobj).html();
        $(thisobj).html(html).find('input').focus().val(val);
        $(thisobj).prop('tabindex', '-1');
    }
    // // 列名称,长度,默认值INPUT框失去焦点事件:框去掉,值写到父级SPAN中
    function field_input_blur(thisobj)
    {
        var parent = $(thisobj).parent('.field-col');
        var val = $(thisobj).val();
        //console.log(val);
        parent.html(val).prop('tabindex', '0');
        //
        refreshEditStatus();
        // 
    }
    // // 列名称,长度,默认值INPUT框支持上下方向键盘切换到上下行同一列
    function field_input_updownArrow(event, thisobj)
    {
        var e = event || window.event;
        // 当前编辑对象在其行内的列索引位置
        var colindex = $(thisobj).parent().index();
        if (e.keyCode == 38)
        {
            // 上一行
            var prevrow = $(thisobj).parent().parent('.fieldrow').prev();
            if (prevrow.length == 1)
            {
                prevrow.children().eq(colindex).focus();
            }
        } else if (e.keyCode == 40)
        {
            // 下一行
            var nextrow = $(thisobj).parent().parent('.fieldrow').next();
            if (nextrow.length == 1)
            {
                nextrow.children().eq(colindex).focus();
            }
        }
        // 按左右键时,如果光标处在文本最右,再按右,则移到后列.如果在最左,再按左,则移到前列
        // 光标焦点位置.如果=文本长度则在最后,为0则在最前
        //console.log($(thisobj).prop('selectionEnd'));
        var position = $(thisobj).prop('selectionEnd');
        if (e.keyCode == 37)
        {
            // 左移动 未考虑左边没有列的情况,因为第1列是主键设置.有本事件的列,其左边至少有一列
            if (position == 0)
            {
                $(thisobj).parent().prev().focus();
            }
        } else if (e.keyCode == 39)
        {
            // 右 未考虑右边没列的情况,有本事件的列不会处于最右边
            if (position == $(thisobj).val().length)
            {
                $(thisobj).parent().next().focus();
            }
        }
    }
    // 列的类型:获得焦点后,其内生成SELECT
    function fieldColType_toSelect(thisobj)
    {
        if ($(thisobj).find('select').length == 1)
            return;
        var selectedval = $(thisobj).attr('val');
        var select = $('#tpl_fieldcol_type_select').html();
        $(thisobj).html(select).prop('tabindex', '-1');
    
        if (selectedval)
        {
            $(thisobj).find('select').focus().find('option[value=' + selectedval + ']').prop('selected', 'selected');
            //console.log($(thisobj).find('select').prop('tabindex'));
        }
    }
    // // 列类型SELECT框失去焦点后,选择值写到val属性上,标题值写到html
    function fieldType_select_blur(thisobj)
    {
        var val = $(thisobj).val();
        var text = $(thisobj).find('option[value=' + val + ']').html();
        $(thisobj).parent('.field-col').html(text).attr('val', val).prop('tabindex', '0');
        //
        refreshEditStatus();
    }
    // // 列类型SELECT框.按左右方向键时,移动到左右相应列上
    function fieldType_select_keydown(event,thisobj)
    {
        // 不考虑左右没有列的情况 ,因为本事件所在列不会处在最左或最右
        var e = event || window.event;
        if (e.keyCode == 37)
        {
            // 左移动 
            $(thisobj).parent().prev().focus();
        } else if (e.keyCode == 39)
        {
            //
            $(thisobj).parent().next().focus();
        }
        return false;
    }
    // 列的说明:获得焦点后,其内生成textarea
    function fieldCol_focus_info(thisobj)
    {
        if ($(thisobj).find('textarea').length == 1)
            return;
        var html = '<textarea class="field-form-control info" onblur="field_input_blur(this)"></textarea>';
        var val = $(thisobj).html();
        $(thisobj).parent('.fieldrow').find('.field-col').addClass('editinfo');
        $(thisobj).html(html).find('textarea').focus().val(val);
        $(thisobj).prop('tabindex', '-1');
    }
    // 在当前行的上面插入一行
    function fieldColOp_click_insertRow(thisobj)
    {
        var row = $(thisobj).parent('.fieldrow');
        var insertrow = row.before($('#tpl_fieldrow').html());
    }
    // 上移下移操作功能:向上或下移动当前行
    function fieldColOp_click_moveRow(thisobj)
    {
        var row = $(thisobj).parent();
        var colindex = row.index();
        if ($(thisobj).hasClass('moverow-up'))
        {
            if (colindex > 1)
            {
                row.insertBefore(row.prev());
            }   
        } else if ($(thisobj).hasClass('moverow-down'))
        {
            if (row.next().length == 1)
                row.insertAfter(row.next());
        }
    }
    // 删除一个列 // 如果没有填写列名,则不提示确认删除
    function fieldCopOp_click_delRow(thisobj)
    {
        var row = $(thisobj).parent('.fieldrow');
        var fieldname = row.find('.field-col').eq(1).html();
        if (fieldname.length == 0)
        {
            row.remove();
            refreshEditStatus();
            return;
        }
        var msg = '确定要删除字段 ' + fieldname + ' ?不可恢复!';
        alertbox(msg,
            function ()
            {
                row.remove();
                refreshEditStatus();
            })
    }
    js
  • 相关阅读:
    memcached +mysql+php 例子
    PHP利用memcache缓存技术提高响应速度
    实现QQ第三方登录教程(php)
    php如何解决多线程同时读写一个文件的问题
    php数组函数常见的那些
    PHP 5种方式获取文件后缀名
    函数与方程
    函数图像习题
    高中数学中需要重点关注的函数和图像
    特殊分段函数的图像画法
  • 原文地址:https://www.cnblogs.com/mirrortom/p/7660577.html
Copyright © 2011-2022 走看看