这次记录一下刚做的一个功能(需求),使用jquery实现表格行自定义顺序,由于实际工作中这个需求涉及到的条件比较多,所以超人鸭就直接按我工作中的情况来讲这个功能,不做模拟。
先看看实现的具体功能:
image.png
表格行的排序是输入框,正常情况下是不可编辑的,当点击上面的编辑排序按钮后,就可以输入想要更换的顺序,并且显示右边的操作按钮:
image.png
点击保存后保存新的排序,并且表格行按排序更换顺序;点击取消排序号返回到编辑前的情况,并且隐藏操作按钮。这里有几个限制条件,第一,排序号不能重复;第二,排序的范围只能在原本的范围内。
知道需求后开始整理思路:
- 输入框只能输入正整数,并且一开始是disable。
- 点击了编辑排序后,输入框全部要取消disable,然后显示后面的操作按钮。
- 点击取消后,排序号要退回到原来的值,所以要保存原本的排序,所以在上一个事件,点击编辑排序按钮的时候,就需要保存原本的排序,用一个数组保存起来,可以用each去遍历输入框,点击取消后要隐藏操作按钮与让输入框变成disable状态。
- 点击保存后,要根据限制条件做校验,先是最大值和最小值,编辑前的排序号已经被我用数组保存起来,所以用这个数组求得正确的最大最小值,然后需要求得编辑后的最大最小值,一样,用一个数组把编辑后的排序保存起来,求得最大最小值,去比较就可以。然后判断是否重复,把编辑后的排序号数组去重,然后和原数组比较长度就可以判断。
- 保存成功后,更换表格的顺序,这项目不是vue的数据渲染,所以只能操作dom,我的思路是用删除表格行再按特定的顺序插进去来实现,这里用到jq两个操作dom的api,prepend和after,那如果获取到特定顺序的表格行呢,需要和输入框的做关联,输入的排序号是输入框的value,用到value选择器:
$("input[value = '1']"),根据这个输入框来获取到表格行。
接下来就是具体实现了,先看看大概的html:
// 表格里面
<table>
<tbody>
<tr>
<td>
<input type="text" name="order-input" disabled onkeyup="changeValue(this)" >
</td>
</tr>
.....
</tbody>
</table>
// 表格上面的按钮
<span class="order-edit-btn">编辑排序</span>
<div style="display: none;">
<button class="save-order-btn">保存</button>
<button class="cancel-order-btn">取消</button>
</div>
大概的html就是这样,因为实际开发还有其他条件,所以都是用class来当选择器。接下来是实现:
- 输入框的限制放在最后,涉及到其他问题,首先点击编辑排序的时候:
var orderList = [] // 保存原排序的数组,全局变量
var maxOrder = 0 // 正确的最大值,全局变量
var minOrder = 0 // 正确的最小值,全局变量
$(".order-edit-btn").click(function () {
$(this).next().show() // 显示操作按钮
$('table').find("input[name='order-input']").attr("disabled",false) // 让序号输入框可以输入
orderList = [] // 重置
$('table').find("input[name='order-input']").each(function(){ // 得到全部序号的数组
orderList.push(parseInt($(this).val()))
})
maxOrder = Math.max.apply(Math,orderList) // 得到最大值
minOrder = Math.min.apply(Math,orderList) // 得到最小值
})
- 点击取消按钮的事件:
$(".cancel-order-btn").click(function() {
$('table').find("input[name='order-input']").each(function (index) { // 让排序号撤回到编辑前的值
$(this).val(orderList[index])
})
$('table').find("input[name='order-input']").attr("disabled",true) // 让序号不可编辑
$(this).parent().hide() // 隐藏操作按钮
})
- 点击保存按钮,需要对新编辑的排序号做校验,所以需要再声明一个数组:
$(".save-order-btn").click(function () {
var newOrderList = [] // 保存编辑后的排序号
$('table').find("input[name='order-input']").each(function() {
newOrderList.push(parseInt($(this).val()))
})
var newMaxOrder = Math.max.apply(Math, newOrderList) // 得到新的最大值
var newMixOrder = Math.min.apply(Math, newOrderList) // 得到新的最小值
// 下面是校验
if (newMixOrder < minOrder) {
alert('最小值不能小于' + minOrder)
return
}
if(newMaxOrder > maxOrder) {
alert('最大值不能小于' + maxOrder)
return
}
newOrderList = newOrderList.filter((x, index, self) => self.indexOf(x) === index) // 去重
if (newOrderList.length < orderList.length) {
alert('不能出现重复序号')
return
}
// 到这里如果没问题排序号就已经更新了,接下来是要实现表格行的更换顺序
/*上面说到,需要先把表格行先删掉,再插入到对应的位置,这里离分为两种情况,第一条也就是序号为一的表格行和其他表格行,如果是第一条表格行就
直接插入到表格的最上面,用到prepend,其他情况就是插到上一个行的后面,用到after,所以需要获取到上一个行的dom,下面看实现
*/
var prevTrDom = null // 保存上一个行的dom
for (var i = minOrder; i <= maxOrder; i++) {
if (i === minOrder) { // 如果是第一行的情况下
let temDom = $("input[name='order-input'][value = " + i + "]").parent().parent() // 保存这个tr的dom,重要
$("input[name='order-input'][value = " + i + "]").parent().parent().remove() // 先将这个dom在表格里面删掉
$('table').find('tbody').prepend(temDom) // 在表格的最前面插入这个行
prevTrDom = temDom // 此时代表上一行的dom就是这一行
} else { // 除了第一行的其他行
let temDom = $("input[name='order-input'][value = " + i + "]").parent().parent() // 同样要先保存
$("input[name='order-input'][value = " + i + "]").parent().parent().remove() // 删掉
prevTrDom.after(temDom) // 插入
prevTrDom = temDom // 更新代表上一行的dom
}
}
$('table').find("input[name='order-input']").attr("disabled", true) // 同样让输入框恢复不可编辑
$(this).parent().hide() // 隐藏操作按钮
})
理论上来说,写到这里除了输入框的限制输入正整数外,需求功能都实现了。但还有一个问题,看上面的实现表格更换顺序,里面最关键的就是获取到与排序号关联的表格行tr:
$("input[name='order-input'][value = " + i + "]").parent().parent()
我用到input的value选择器,注意里面如果要写变量要想我那样写,不然 i 会被识别成字符串。可能是之前做的都是vue的项目,都习惯了数据的双向绑定与动态更新,但是在原生dom里面的输入框,当你输入后,它的value是不会实时更新的:
image.png
可以看到还是我改变前输入的值,所以上面说到的排序号,虽然我编辑了,输入框的值改变了,但是它的value还是没有变,所以上面的实现表格更换顺序会没有反应,所以现在的问题就是实现输入框一输入,它的value就会更新,超人鸭在百度找到了一个方法,刚好可以和限制输入框只能输入正整数写在一起。还记得我上面写的输入框的html代码吗?
<input type="text" name="order-input" disabled onkeyup="changeValue(this)" >
监听输入框的onkeyup事件:
function changeValue(obj) {
$(obj).attr("value",$(obj).val().replace(/^(0+)|[^\d]+/g,''));
}
实现了输入框vlaue的实时更新与正则匹配过滤掉非正整数。
到这里就完成了所说的功能,欢迎留言指教。
作者微信: ***Promise_fulfilled ***
网友评论