Django前端HTML通过JS实现表格可编辑,动态添加行,回车完成新建文件夹
版本:
django:2.1.7
python:3.7
功能描述:
点击“新建文件夹”按钮,在table的末尾增加一行;单击页面的新增行,使单元格td变成可编辑状态;输入内容后,当单元格失去焦点时,保存输入的内容;回车后通过AJAX提交后台完成新建文件夹。
HTML部分代码,id="table2"和EditType="TextBox"后面需要用到。
<button class="btn btn-default" type="button" id="create_dir" name="create_dir" value="create_dir" style='margin-left:10px;margin-right:10px;color:rgb(60, 141, 188);' onclick="AddRow($('#table2')[0],1)">新建文件夹</button> <table id="table2" class="table table-hover" style="overflow: auto;" > <tr> <td class='th3' EditType="TextBox"> <img src="/static/img/file4_24.ico"> {% if fileinfo.search_flag == 0 %} {{ fileinfo.file_name }} {% else %} {{ fileinfo.file_path }} {% endif %} </td> </tr>
样式表格td部分,新增行改一下:
{% block style %} <style> td{ border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCCCCC; } .EditCell_TextBox { width: 90%; border:1px solid #0099CC; } .EditCell_DropDownList { width: 90%; } </style> {% endblock %}
JS部分,也是最关键的一部分:
{% block javascripts %} <script> /** * JS实现可编辑的表格 * 用法:EditTables(tb1,tb2,tb2,......); **/ //添加行 function AddRow(table, index){ var lastRow = table.rows[table.rows.length-1]; var newRow = lastRow.cloneNode(true); //计算新增加行的序号,需要引入jquery 的jar包 var startIndex = $.inArray(lastRow,table.rows); var endIndex = table.rows; table.tBodies[0].appendChild(newRow); // newRow.cells[0].innerHTML=endIndex-startIndex; newRow.cells[1].innerHTML="新建文件夹"; // <img src='/static/img/folder_24.ico'> // console.log(newRow.cells[0].innerHTML); SetRowCanEdit(newRow); return newRow; } function SetRowCanEdit(row){ // console.log(row.cells.length); for(var j=0;j<row.cells.length; j++){ //如果当前单元格指定了编辑类型,则表示允许编辑 var editType = row.cells[j].getAttribute("EditType"); if(!editType){ //如果当前单元格没有指定,则查看当前列是否指定 editType = row.parentNode.rows[0].cells[j].getAttribute("EditType"); } if(editType){ //新建后直接处于可编辑状态 EditCell(row.cells[j]); row.cells[j].onclick = function (){ EditCell(this); } } } } //设置指定单元格可编辑 function EditCell(element, editType){ var editType = element.getAttribute("EditType"); if(!editType){ //如果当前单元格没有指定,则查看当前列是否指定 editType = element.parentNode.parentNode.rows[0].cells[element.cellIndex].getAttribute("EditType"); } switch(editType){ case "TextBox": CreateTextBox(element, element.innerHTML); break; default: break; } } //为单元格创建可编辑输入框 function CreateTextBox(element, value){ //检查编辑状态,如果已经是编辑状态,跳过 var editState = element.getAttribute("EditState"); if(editState != "true"){ //创建文本框 var textBox = document.createElement("INPUT"); textBox.type = "text"; textBox.className="EditCell_TextBox"; // value = "新建文件夹" //设置文本框当前值 if(!value){ value = element.getAttribute("Value"); } textBox.value = value; //设置文本框的失去焦点事件 textBox.onblur = function (){ CancelEditCell(this.parentNode, this.value); } //向当前单元格添加文本框 ClearChild(element); element.appendChild(textBox); textBox.focus(); textBox.select(); //改变状态变量 element.setAttribute("EditState", "true"); element.parentNode.parentNode.setAttribute("CurrentRow", element.parentNode.rowIndex); //回车事件 textBox.onkeypress = function(event){ // console.log(element.innerHTML); // console.log(this.value); if (event.keyCode == "13"){ $.ajax({ url:"/create_dir?dir_name="+this.value, // url:"{% url 'upload_files' %}", type:"GET", data:'', // processData:false, contentType:false, success:function (data) { // console.log(data) // alert("创建文件夹完成!"); history.go(0); } }); } } } } //取消单元格编辑状态 function CancelEditCell(element, value, text){ element.setAttribute("Value", value); if(text){ element.innerHTML = text; }else{ element.innerHTML = value; } element.setAttribute("EditState", "false"); //检查是否有公式计算 CheckExpression(element.parentNode); } //清空指定对象的所有字节点 function ClearChild(element){ element.innerHTML = ""; } //提取指定行的数据,JSON格式 function GetRowData(row){ var rowData = {}; for(var j=0;j<row.cells.length; j++){ name = row.parentNode.rows[0].cells[j].getAttribute("Name"); if(name){ var value = row.cells[j].getAttribute("Value"); if(!value){ value = row.cells[j].innerHTML; } rowData[name] = value; } } //alert("ProductName:" + rowData.ProductName); //或者这样:alert("ProductName:" + rowData["ProductName"]); return rowData; } //检查当前数据行中需要运行的字段 function CheckExpression(row){ for(var j=0;j<row.cells.length; j++){ expn = row.parentNode.rows[0].cells[j].getAttribute("Expression"); //如指定了公式则要求计算 if(expn){ var result = Expression(row,expn); var format = row.parentNode.rows[0].cells[j].getAttribute("Format"); if(format){ //如指定了格式,进行字值格式化 row.cells[j].innerHTML = formatNumber(Expression(row,expn), format); }else{ row.cells[j].innerHTML = Expression(row,expn); } } } } //计算需要运算的字段 function Expression(row, expn){ var rowData = GetRowData(row); //循环代值计算 for(var j=0;j<row.cells.length; j++){ name = row.parentNode.rows[0].cells[j].getAttribute("Name"); if(name){ var reg = new RegExp(name, "i"); expn = expn.replace(reg, rowData[name].replace(/\,/g, "")); } } return eval(expn); } $(function() { var tabProduct = document.getElementById("table2"); // 设置表格可编辑 // 可一次设置多个,例如:EditTables(tb1,tb2,tb2,......) // EditTables(tabProduct); // console.log('test!!!!!!!!!!!!!!'); }); </script> {% endblock %}
JS部分根据自己的需求优化了一下:
1.EditTables()设置多个表格不要了,我只需要编辑新增行就行了。而且innerHTML会被看到td中代码。
2.tabProduct获取自己table的id。
3.新增按钮onclick="AddRow($('#table2')[0],1)",参数为自己表对象,注意[0]。AddRow中可以改新增行默认内容,我的为“新建文件夹”。
4.SetRowCanEdit()函数中增加如下代码,使新增行后直接处于可编辑状态,也可以单击进入编辑状态。
EditCell(row.cells[j]);
5.CreateTextBox()中获取用户输入的值,增加捕获键盘回车事件后,通过AJAX提交后台:
textBox.onkeypress = function(event){ if (event.keyCode == "13"){ $.ajax({ url:"/create_dir?dir_name="+this.value, type:"GET", data:'', // processData:false, contentType:false, success:function (data) { // alert("创建文件夹完成!"); history.go(0); } }); } }
6.python后台实现新建文件夹,AJAX异步处理后返回直接更新目录,不需要刷新:
def create_dir(request): if request.method == 'GET': dir_name = request.GET.get('dir_name') print('create_dir:'+dir_name) path = os.path.join(current_path,dir_name) while os.path.exists(path): path += '-副本' os.makedirs(r'%s'%path) return HttpResponse(path) else: return HttpResponse("error")
7.这样空表格的时候新建行还是会出问题,因为是克隆最后一行新建的,所有空表格时需要自己动态的新建一个行,DataTable.js空表格时会有提示“空表格”的一行,所有先deleteRow删除行,再insertRow插入行。最后创建可编辑单元,和单机触发。
代码如下:
function AddRow(table, index){ var lastRow = table.rows[table.rows.length-1]; var newRow = lastRow.cloneNode(true); //计算新增加行的序号,需要引入jquery 的jar包 if(newRow.cells.length > 1){ newRow.cells[1].innerHTML="新建文件夹"; table.tBodies[0].appendChild(newRow); SetRowCanEdit(newRow); }else{ table.deleteRow(1); newRow = table.insertRow(1); newRow.insertCell(0).innerHTML = "<td><input type='checkbox'/></td>"; newRow.insertCell(1).innerHTML = "<td>新建文件夹</td>"; newRow.insertCell(2).innerHTML = "<td>-</td>"; newRow.insertCell(3).innerHTML = "<td>-</td>"; newRow.insertCell(4).innerHTML = "<td>-</td>"; newRow.insertCell(5).innerHTML = "<td>-</td>"; newRow.insertCell(6).innerHTML = "<td>-</td>"; newRow.insertCell(7).innerHTML = "<td>-</td>"; CreateTextBox(newRow.cells[1],newRow.cells[1].innerHTML); newRow.cells[1].onclick = function (){ CreateTextBox(this,this.innerHTML); } } return newRow; }
8.最后,效果如下: