• 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: '头条标题', 200}
              ,{field: 'contributor', title: '投稿人'}
              ,{field: 'category', title: '头条类型'}
              ,{field: 'contact', title: '联系方式'}
              ,{
                  title: '投稿时间',
                   200,
                  templet: '<div>{{layui.util.toDateString(d.createTime, "yyyy-MM-dd HH:mm:ss")}}</div>'
              }
              ,{
                  title: '审核状态',  200, templet: function (d) {
                    switch (d.checkStatus) {
                      case 0:
                        return '<div>待审核</span>';
                      case 1:
                        return '<div>审核通过</span>';
                      default:
                        return '<div>审核不通过</span>';
                    }
                  }
                }
                ,{
                    title: '审核时间',
                     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)刷新两遍的问题

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

  • 相关阅读:
    js中剩余参数
    css中 @mixin的使用
    前端Vue中常用rules校验规则
    vue 运行时报错: Cannot assign to read only property 'exports' of object 'Object'
    webpack 常用的loader
    二维码图片合成 ----合成图片以便微信长按保存(移动端)
    VUE中引入第三方JS
    小程序开发者工具--快捷键
    小程序注意事项
    webpack+ES6+less 开发环境搭建
  • 原文地址:https://www.cnblogs.com/kendoziyu/p/16189612.html
Copyright © 2020-2023  润新知