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>
filter = (events ¦¦ '').match(/((.*))$/)¦¦[]

//提取事件过滤器字符结构
eventName = (modName + '.'+ events).replace(filter[0], '')
//获取事件名称
"form.select" "form.select"
filterName = filter[1] ¦¦ ''

//获取过滤器名称
"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 }); 只执行了一次。

结论,到底是怎么刷新两遍的?

所以刷新两遍就是:

  1. table.reload('dataTable', { where: data.field }); 第一次刷新;
  2. <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>

参考文档

layui数据表格筛选或搜索(reload)刷新两遍的问题

这篇文章其实已经指出了问题所在和解决方案,但是我本着刨根问底的态度,才写了本文。

posted @ 2022-04-25 18:01  极客子羽  阅读(2780)  评论(0编辑  收藏  举报