layui数据表格点击搜索查询表单刷新两遍的问题详解
今天我又遇到了一个问题,layui 的数据表格 reload 时刷新两遍的问题。点击“查询”,页面会闪烁一下,并且搜索条中输入的条件会清空。
上边用了 layui form 做了一个搜索条,下边用 layui table 实现数据表格。
浏览器_form_submit
以下是带有输入框和确认按钮的表单:
<!DOCTYPE html>
<html>
<body>
<form>
搜索标题:<input name="newsTitle" value="Hello~">
<button>提交</button>
</form>
</body>
</html>
即使是这样简单的一段代码,在你点击 “提交” 时,也会产生一个HTTP请求。
比如,我把以上代码保存在桌面的文本文档(txt 文件)中,并重命名为 search.html :
接着,右击该文件,选择 打开方式为 Google Chrome:
接着点击 提交:
浏览器地址栏中发生了变化,增加了查询参数 ?newsTitle=Hello~。
该现象产生的原因是 <form> 在缺省情况下 method="GET" (了解更多 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/form#attr-method)
如果修改为<form method="post">
,点击“提交”按钮以后,浏览器地址栏URL将不发生重定向。
这是 <form> + <button type="submit"> 组合使用的效果,浏览器解析到这样的标签组合,就会给这个按钮提供将表单数据提交给服务器的功能!!
当你不指定 <button> 的 type 属性时,它的默认值就是 submit:
以上截图截取自 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/button
解决方案一:拆散form_submit组合
既然浏览器检查到元素 <form> + <button type="submit">,会自动提供提交表单(即刷新页面)的功能,那我们就通过修改 button 来取消这种默认行为!!
使用 <button class="layui-btn" type="button">搜索</button>
或者 <input class="layui-btn" type="button" value="搜索"></input>
替换 <button>提交</button>
layui.form.on_lay-filter
首先,执行 form.js 中的初始化函数:
以上代码使用的是 jQuery 语法:
$(selector).on(event,childSelector,data,function)
代码解释:
在包含class="layui-form"
的元素上添加 "submit" 事件的处理程序,事件发生时的回调函数是submit
;
在所有包含lay-submit
属性的元素上添加 "click" 事件的处理程序,事件发生时的回调函数也是submit
;了解更多 CSS选择器 https://www.runoob.com/cssref/css-selectors.html
form.js中的submit函数
页面正常显示之后,用户点击“查询”时,回调函数 submit
被触发,以下对比一下 submit
触发时的局部变量:
包含 lay-submit 属性的元素的 click 事件触发回调函数 |
包含 class="layui-form" 的表单的submit事件触发回调函数 |
|
---|---|---|
button = $(this) //当前触发的按钮 |
<button class="layui-btn" lay-submit="" lay-filter="search">查询</button> |
<form class="layui-form">...省略</form> |
elem = button.parents(ELEM).eq(0) //当前所在表单域 |
<form class="layui-form">...省略</form> |
找不到 |
verifyElem = elem.find('*[lay-verify]') //获取需要校验的元素 |
找不到,因为我没在 <button> 上加 lay-verify 属性 |
没找到 |
formElem = button.parents('form')[0] //获取当前所在的 form 元素,如果存在的话 |
<form class="layui-form">...省略</form> |
undefined |
★filter = button.attr('lay-filter') //获取过滤器 |
"search" | undefined |
★this |
<button class="layui-btn" lay-submit="" lay-filter="search">查询</button> |
<form class="layui-form">...省略</form> |
首先,包含 lay-submit
属性的元素的 click 事件触发回调函数时,运行到 submit
函数的最后:
layui.js中的Layui.prototype.event
两次执行自定义模块事件 Layui.prototype.event 的本地变量对比:
<button class="layui-btn" lay-submit="" lay-filter="search"> 触发事件 |
<form class="layui-form"> 触发事件 |
|
---|---|---|
events | "submit(search)" | "submit(undefined)" |
var that = this | <button> |
<form> |
//提取事件过滤器字符结构 |
||
eventName = (modName + '.'+ events).replace(filter[0], '') //获取事件名称 |
"form.select" | "form.select" |
//获取过滤器名称 |
"search" | "undefined" |
是否触发自定义模块事件的关键判断在
其中 config.event 对应 form.on('submit(search)', function (data) { ... });
这段代码:
因为,此时 key 的值为 "search"
所以 key === '' 结果为 false,所以发生“短路”(即&& layui.each(item, callback)
不会执行。)
<button class="layui-btn" lay-submit="" lay-filter="search"> 触发事件 |
<form class="layui-form"> 触发事件 |
|
---|---|---|
filterName | "search" | "undefined" |
(filterName && key === filterName) |
true | false |
&& layui.each(item, callback) |
会执行 | 不会执行 |
总而言之,form.on('submit(search)', function (data) {...});
中回调函数 table.reload('dataTable', { where: data.field });
只执行了一次。
结论,到底是怎么刷新两遍的?
所以刷新两遍就是:
table.reload('dataTable', { where: data.field });
第一次刷新;- <form> 和 <button type="submit" /> 组合,又让浏览器进行了一次表单提交,第二次刷新;
$(selector).on_return false
因为 form.js 中用的是 jquery 语法注册事件,且我跟了一遍源码后发现,用户函数中返回值,在每一层调用中都有返回,所以,可以简化 search.html 为
<!DOCTYPE html>
<html>
<body>
<form>
搜索标题:<input name="newsTitle" value="Hello~">
<button>提交</button>
</form>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).on('click', 'button', function() {
console.log('clicked');
return false;
});
</script>
</body>
</html>
此时,点击“提交”不会提交form表单,即不会产生http请求。
参考文档:
javascript事件中'return false'详解
https://www.w3.org/TR/DOM-Level-3-Events/#event-flow-default-cancel
解决方案2:return false取消事件默认行为(default action)
本文之前就已经提供了 解决方案一:拆散form_submit组合,现在提供第二种思路 return false取消事件默认行为(default action)。
★ 在本例中,与 <button type="submit"/> 上的 click 事件相关联的默认操作(default action)将表单(<form>)数据提交给服务器。如果 click 事件的默认操作被取消,则不再将发出http请求!
form.on('submit(search)', function (data) {
table.reload('dataTable', {
where: data.field
});
return false;
});
我试过用 preventDefault() 代替 return false ,但是事实上没效果,应该和浏览器实现有关系。
参考源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="http://www.layuicdn.com/layui/css/layui.css" />
</head>
<body>
<!-- layui的form表单一行显示多个文本框 https://www.cnblogs.com/Tpf386/p/12673356.html -->
<!-- 搜索条 -->
<div class="layui-row">
<form class="layui-form">
<div class="layui-form-item">
<!-- 搜索标题 -->
<label class="layui-form-label" for="newsTitle">搜索标题:</label>
<div class="layui-input-inline">
<input class="layui-input" name="newsTitle" id="newsTitle" value="">
</div>
<!-- 审核状态 -->
<label class="layui-form-label" for="checkStatus">审核状态:</label>
<div class="layui-input-inline">
<select id="checkStatus" name="checkStatus" lay-filter="checkStatus">
<option value="">请选择</option>
<option value="0">待审核</option>
<option value="1">审核通过</option>
<option value="2">审核不通过</option>
</select>
</div>
<!-- 问题代码 -->
<!--<button class="layui-btn" lay-submit="" lay-filter="search">查询</button>-->
<input class="layui-btn" type="button" value="查询" lay-submit lay-filter="search" />
</div>
</form>
</div>
<!--数据表格-->
<table id="dataTable" lay-filter="dataTable"></table>
<script type="text/javascript" src="http://www.layuicdn.com/layui/layui.js"></script>
<!-- layui.js下载到本地方便调试 -->
<!--<script type="text/javascript" src="/static/layui/layui.js"></script>-->
<script type="text/javascript">
layui.use(['form', 'table'], function() {
var form = layui.form
,table = layui.table;
form.on('submit(search)', function (data) {
table.reload('dataTable', {
where: data.field
});
});
table.render({
elem: '#dataTable'
, contentType: 'application/json'
, url: '/api/news/list.do'
, method: 'post'
, page: true
, cols: [
[ //表头
{fixed: 'left', type: "numbers"}
,{field: 'newsTitle', title: '头条标题', width:200}
,{field: 'contributor', title: '投稿人'}
,{field: 'category', title: '头条类型'}
,{field: 'contact', title: '联系方式'}
,{
title: '投稿时间',
width: 200,
templet: '<div>{{layui.util.toDateString(d.createTime, "yyyy-MM-dd HH:mm:ss")}}</div>'
}
,{
title: '审核状态', width: 200, templet: function (d) {
switch (d.checkStatus) {
case 0:
return '<div>待审核</span>';
case 1:
return '<div>审核通过</span>';
default:
return '<div>审核不通过</span>';
}
}
}
,{
title: '审核时间',
width: 200,
templet: '<div>{{layui.util.toDateString(d.createTime, "yyyy-MM-dd HH:mm:ss")}}</div>'
},{
title: '操作',
templet: function (d) {
switch (d.checkStatus) {
case 0:
return '<span class="layui-btn layui-btn-xs">审核</span>';
default:
return '<span class="layui-btn layui-btn-xs">再次审核</span>';
}
}
}
]
]
});
});
</script>
</body>
</html>
参考文档
这篇文章其实已经指出了问题所在和解决方案,但是我本着刨根问底的态度,才写了本文。