关于layui的一些故事(一):数据表格和其他记录


一、数据表格渲染方法

三种初始化渲染方式

方式 机制 适用场景
01. 方法渲染 用JS方法的配置完成渲染 (推荐)无需写过多的 HTML,在 JS 中指定原始元素,再设定各项参数即可。
02. 自动渲染 HTML配置,自动渲染 无需写过多 JS,可专注于 HTML 表头部分
03. 转换静态表格 转化一段已有的表格元素 无需配置数据接口,在JS中指定表格元素,并简单地给表头加上自定义属性即可

1.方法渲染

其实这是“自动化渲染”的手动模式,本质类似,只是“方法级渲染”将基础参数的设定放在了JS代码中,且原始的 table 标签只需要一个 选择器

<table id="demo" lay-filter="test"></table>
var table = layui.table;

//执行渲染
table.render({
    elem: '#demo', //指定原始表格元素选择器(推荐id选择器)
    height: 315, //容器高度
    cols: [{}] //设置表头
    //,…… //更多参数参考右侧目录:基本参数选项
});  

更推荐采用“方法级渲染”的做法,其最大的优势在于你可以脱离HTML文件,而专注于JS本身。尤其对于项目的频繁改动及发布,其便捷性会体现得更为明显。

2.自动渲染

所谓的自动渲染,即:在一段 table 容器中配置好相应的参数,由 table 模块内部自动对其完成渲染,而无需你写初始的渲染方法。你需要关注的是以下三点:

  1. 带有 class=”layui-table”<table> 标签。
  2. 对标签设置属性 lay-data=”” 用于配置一些基础参数
  3. <th> 标签中设置属性lay-data=””用于配置表头信息

按照上述的规范写好table原始容器后,只要你加载了layui 的 table 模块,就会自动对其建立动态的数据表格。

<table class="layui-table" lay-data="{height:315, url:'/demo/table/user/', page:true, id:'test'}" lay-filter="test">
    <thead>
        <tr>
            <th lay-data="{field:'id', width:80, sort: true}">ID</th>
            <th lay-data="{field:'username', width:80}">用户名</th>
            <th lay-data="{field:'sex', width:80, sort: true}">性别</th>
            <th lay-data="{field:'city'}">城市</th>
            <th lay-data="{field:'sign'}">签名</th>
            <th lay-data="{field:'experience', sort: true}">积分</th>
            <th lay-data="{field:'score', sort: true}">评分</th>
            <th lay-data="{field:'classify'}">职业</th>
            <th lay-data="{field:'wealth', sort: true}">财富</th>
        </tr>
    </thead>
</table>

3.转换静态表格

假设你的页面已经存在了一段有内容的表格,它由原始的table标签组成,这时你需要赋予它一些动态元素,那么你可以在你的静态表格的 th 标签中加上 lay-data="" 属性,

<table lay-filter="demo">
    <thead>
        <tr>
            <th lay-data="{field:'username', width:100}">昵称</th>
            <th lay-data="{field:'experience', width:80, sort:true}">积分</th>
            <th lay-data="{field:'sign'}">签名</th>
        </tr> 
    </thead>
    <tbody>
        <tr>
            <td>贤心1</td>
            <td>66</td>
            <td>人生就像是一场修行a</td>
        </tr>
        <tr>
            <td>贤心2</td>
            <td>88</td>
            <td>人生就像是一场修行b</td>
        </tr>
        <tr>
            <td>贤心3</td>
            <td>33</td>
            <td>人生就像是一场修行c</td>
        </tr>
    </tbody>
var table = layui.table;
//转换静态表格
table.init('demo', {
    height: 315 //设置高度
    ,limit: 10 //注意:请务必确保 limit 参数(默认:10)是与你服务端限定的数据条数一致
    //支持所有基础参数
})

在前面的“方法渲染”和“自动渲染”两种方式中,你的数据都来源于异步的接口,这可能并不利于所谓的seo(当然是针对于前台页面)。而在这里,你的数据已和页面同步输出,却仍然可以转换成动态表格。

二、异步数据接口

数据的异步请求由以下几个参数组成:

参数名 功能
url 接口地址。默认会自动传递两个参数:?page=1&limit=30*(该参数可通过 request 自定义) *page 代表当前页码、limit 代表每页数据量
method 接口http请求类型,默认:get
where 接口的其它参数。如:where: {token: ‘sasasas’, id: 123}
contentType 发送到服务端的内容编码类型。如果你要发送 json 内容,可以设置:contentType: ‘application/json’
headers 接口的请求头。如:headers: {token: ‘sasasas’}

parseData

数据格式解析的回调函数,用于将返回的任意数据格式解析成 table 组件规定的数据格式。

table 组件默认规定的数据格式为(参考:/demo/table/user/):

//默认规定的数据格式
{
  "code": 0,
  "msg": "",
  "count": 1000,
  "data": [{}, {}]
} 

很多时候,您接口返回的数据格式并不一定都符合 table 默认规定的格式,比如:

//假设您返回的数据格式
{
  "status": 0,
  "message": "", 
  "total": 180, 
  "data": {
    "item": [{}, {}]
  }
}

那么你需要借助 parseData 回调函数将其解析成 table 组件所规定的数据格式

table.render({
  elem: '#demp'
  ,url: ''
  ,parseData: function(res){ //res 即为原始返回的数据
    return {
      "code": res.status, //解析接口状态
      "msg": res.message, //解析提示文本
      "count": res.total, //解析数据长度
      "data": res.data.item //解析数据列表
    };
  }
  //,…… //其他参数
});    

request

用于对分页请求的参数:page、limit重新设定名称,如:

table.render({
  elem: '#demp'
  ,url: ''
  ,request: {
    pageName: 'curr' //页码的参数名称,默认:page
    ,limitName: 'nums' //每页数据量的参数名,默认:limit
  }
  //,…… //其他参数
}); 
//那么请求数据时的参数将会变为:?curr=1&nums=30

response

您还可以借助 response 参数来重新设定返回的数据格式,如:

table.render({
  elem: '#demp'
  ,url: ''
  ,response: {
    statusName: 'status' //规定数据状态的字段名称,默认:code
    ,statusCode: 200 //规定成功的状态码,默认:0
    ,msgName: 'hint' //规定状态信息的字段名称,默认:msg
    ,countName: 'total' //规定数据总数的字段名称,默认:count
    ,dataName: 'rows' //规定数据列表的字段名称,默认:data
  } 
  //,…… //其他参数
});     
//重新规定的数据格式:
{
  "status": 200,
  "hint": "",
  "total": 1000,
  "rows": []
}

三、数据表格基础方法调用

  1. > table.set(options); //设定全局默认参数。options即各项基础参数
  2. > table.on(‘event(filter)’, callback); //事件监听。event为内置事件名,filter为容器lay-filter设定的值
  3. > table.init(filter, options); //filter为容器lay-filter设定的值,options即各项基础参数,详见:转换静态表格
  4. > table.checkStatus(id); //获取表格选中行。id 即为 id 参数对应的值
  5. > table.render(options); //用于表格方法级渲染,核心方法。详见:方法级渲染
  6. > table.reload(id, options); //表格重载
  7. > table.resize(id); //重置表格尺寸
  8. > table.exportFile(id, data, type); //导出数据

1.获取选中行

该方法可获取到表格所有的选中行相关数据

语法:table.checkStatus('ID')

var checkStatus = table.checkStatus('idTest'); //idTest 即为基础参数 id 对应的值
console.log(checkStatus.data) //获取选中行的数据
console.log(checkStatus.data.length) //获取选中行数量,可作为是否有选中行的条件
console.log(checkStatus.isAll ) //表格是否全选

2.表格重载

语法 说明 适用场景
table.reload(ID, options) 参数 ID 即为基础参数id对应的值,options 即为各项基础参数 所有渲染方式
tableIns.reload(options) 参数同上
tableIns 可通过 var tableIns = table.render() 得到
仅限方法级渲染

自动化渲染的重载

<table class="layui-table" lay-data="{id: 'idTest'}"> 
</table>
table.reload('idTest', {
  url: '/api/table/search'
  ,where: {} //设定异步数据接口的额外参数
});

方法级渲染的重载

//所获得的 tableIns 即为当前容器的实例
var tableIns = table.render({
    elem: '#id'
    ,cols: [] //设置表头
    ,url: '/api/data' //设置异步接口
    ,id: 'idTest'
}); 

//这里以搜索为例
tableIns.reload({
    where: { //设定异步数据接口的额外参数,任意设
        aaaaaa: 'xxx'
        ,bbb: 'yyy'
        //…
    }
    ,page: {
        curr: 1 //重新从第 1 页开始
    }
});
//上述方法等价于
table.reload('idTest', {
    where: { //设定异步数据接口的额外参数,任意设
        aaaaaa: 'xxx'
        ,bbb: 'yyy'
        //…
    }
    ,page: {
        curr: 1 //重新从第 1 页开始
    }
}); //只重载数据

注意:这里的表格重载是指对表格重新进行渲染,包括数据请求和基础参数的读取

3.导出任意数据

尽管 table 的工具栏内置了数据导出按钮,但有时你可能需要通过方法去导出任意数据,那么可以借助以下方法:

语法:table.exportFile(id, data, type)

var ins1 = table.render({
  elem: '#demo'
  ,id: 'test'
  //,…… //其它参数
})      

//将上述表格示例导出为 csv 文件
table.exportFile(ins1.config.id, data); //data 为该实例中的任意数量的数据

//事实上,该方法也可以不用依赖 table 的实例,可直接导出任意数据:
table.exportFile(['名字','性别','年龄'], [
  ['张三','男','20'],
  ['李四','女','18'],
  ['王五','女','19']
], 'csv'); //默认导出 csv,也可以为:xls

4.templet - 自定义列模板

在默认情况下,单元格的内容是完全按照数据接口返回的content原样输出的,如果你想对某列的单元格添加链接等其它元素,你可以借助该参数来轻松实现。这是一个非常实用且强大的功能,你的表格内容会因此而丰富多样。

templet 提供了三种使用方式,请结合实际场景选择最合适的一种:

  • 如果自定义模版的字符量太大,我们推荐你采用【方式一】;
  • 如果自定义模板的字符量适中,或者想更方便地调用外部方法,我们推荐你采用【方式二】;
  • 如果自定义模板的字符量很小,我们推荐你采用【方式三】

方式一:绑定模版选择器

table.render({
  cols: [[
    {field:'title', title: '文章标题', width: 200, templet: '#titleTpl'} //这里的templet值是模板元素的选择器
    ,{field:'id', title:'ID', width:100}
  ]]
});

//等价于:
<th lay-data="{field:'title', width: 200, templet: '#titleTpl'}">文章标题</th>
<th lay-data="{field:'id', width:100}">ID</th>

下述是templet对应的模板,它可以存放在页面的任意位置。模板遵循于 laytpl 语法,可读取到返回的所有数据

<script type="text/html" id="titleTpl">
  <a href="/detail/{{d.id}}" class="layui-table-link">{{d.title}}</a>
</script>

<!--注意:上述的 {{d.id}}、{{d.title}} 是动态内容,它对应数据接口返回的字段名。除此之外,你还可以读取到以下额外字段:序号:{{ d.LAY_INDEX }} (该额外字段为 layui 2.2.0 新增)-->

<!--由于模板遵循 laytpl 语法(建议细读 laytpl文档 ),因此在模板中你可以写任意脚本语句(如 if else/for等): -->
<script type="text/html" id="titleTpl">
  {{#  if(d.id < 100){ }}
    <a href="/detail/{{d.id}}" class="layui-table-link">{{d.title}}</a>
  {{#  } else { }}
    {{d.title}}(普通用户)
  {{#  } }}
</script>

方式二:函数转义

templet 开始支持函数形式,函数返回一个参数 d,包含接口返回的所有字段和数据。如下所示:

table.render({
  cols: [[
    {field:'title', title: '文章标题', width: 200
      ,templet: function(d){
        return 'ID:'+ d.id +',标题:<span style="color: #c00;">'+ d.title +'</span>'
      }
    }
    ,{field:'id', title:'ID', width:100}
  ]]
}); 

方式三:直接赋值模版字符

事实上,templet 也可以直接是一段 html 内容,如:

templet: '<div><a href="/detail/{{d.id}}" class="layui-table-link">{{d.title}}</a></div>'

//注意:这里一定要被一层 <div></div> 包裹,否则无法读取到模板

5.done- 数据渲染完的回调

无论是异步请求数据,还是直接赋值数据,都会触发该回调。你可以利用该回调做一些表格以外元素的渲染。

table.render({ //其它参数在此省略
  done: function(res, curr, count){
    //如果是异步请求数据方式,res即为你接口返回的信息。
    //如果是直接赋值的方式,res即为:{data: [], count: 99} data为当前页数据、count为数据总长度
    console.log(res);
    //得到当前页码
    console.log(curr); 
    //得到数据总量
    console.log(count);
  }
});

四、数据表格事件监听

语法:table.on('event(filter)', callback); 注:event为内置事件名,filter为容器lay-filter设定的值

table模块在Layui事件机制中注册了专属事件,如果你使用layui.onevent()自定义模块事件,请勿占用table名。目前所支持的所有事件。

默认情况下,事件所监听的是全部的table模块容器,但如果你只想监听某一个容器,使用事件过滤器即可。

假设原始容器为:<table class="layui-table" lay-filter="test"></table> 那么你的事件监听写法如下:

//以复选框事件为例
table.on('checkbox(test)', function(obj){
  console.log(obj)
})

1.监听头部工具栏事件

1-1.toolbar

开启表格头部工具栏区域,该参数支持四种类型值:

  • toolbar: '#toolbarDemo' //指向自定义工具栏模板选择器
  • toolbar: '<div>xxx</div>'//直接传入工具栏模板字符
  • toolbar: true//仅开启工具栏,不显示左侧模板
  • toolbar: 'default'//让工具栏左侧显示默认的内置模板

若需要“列显示隐藏”、“导出”、“打印”等功能,则必须开启该参数

点击头部工具栏区域设定了属性为 lay-event="" 的元素时触发

<!-- 原始容器 -->
<table id="demo" lay-filter="test"></table>
工具栏模板:
<script type="text/html" id="toolbarDemo">
  <div class="layui-btn-container">
    <button class="layui-btn layui-btn-sm" lay-event="add">添加</button>
    <button class="layui-btn layui-btn-sm" lay-event="delete">删除</button>
    <button class="layui-btn layui-btn-sm" lay-event="update">编辑</button>
  </div>
</script>
//JS 调用:
table.render({
  elem: '#demo'
  ,toolbar: '#toolbarDemo'
  //,…… //其他参数
});

//监听事件
table.on('toolbar(test)', function(obj){
  var checkStatus = table.checkStatus(obj.config.id);
  switch(obj.event){
    case 'add':
      layer.msg('添加');
    break;
    case 'delete':
      layer.msg('删除');
    break;
    case 'update':
      layer.msg('编辑');
    break;
  };
});

1-2.defaultToolbar

类型:Array,默认值:["filter","exports","print"]

该参数可自由配置头部工具栏右侧的图标按钮,值为一个数组,支持以下可选值:

  • filter: 显示筛选图标
  • exports: 显示导出图标
  • print: 显示打印图标

可根据值的顺序显示排版图标,如:

defaultToolbar: ['filter', 'print', 'exports']

table.render({ //其它参数在此省略      
    defaultToolbar: ['filter', 'print', 'exports', {
        title: '提示' //标题
        ,layEvent: 'LAYTABLE_TIPS' //事件名,用于 toolbar 事件中使用
        ,icon: 'layui-icon-tips' //图标类名
    }]
});

2.监听复选框选择

点击复选框时触发,回调函数返回一个 object 参数,携带的成员如下:

table.on('checkbox(test)', function(obj){
    console.log(obj.checked); //当前是否选中状态
    console.log(obj.data); //选中行的相关数据
    console.log(obj.type); //如果触发的是全选,则为:all,如果触发的是单选,则为:one
});

3.监听单元格编辑

单元格被编辑,且值发生改变时触发,回调函数返回一个 object 参数,携带的成员如下:

table.on('edit(test)', function(obj){ //注:edit是固定事件名,test是table原始容器的属性 lay-filter="对应的值"
    console.log(obj.value); //得到修改后的值
    console.log(obj.field); //当前编辑的字段名
    console.log(obj.data); //所在行的所有相关数据  
});

4.监听行单双击事件

点击或双击行时触发。

//监听行单击事件
table.on('row(test)', function(obj){
    console.log(obj.tr) //得到当前行元素对象
    console.log(obj.data) //得到当前行数据
    //obj.del(); //删除当前行
    //obj.update(fields) //修改当前行数据
});

//监听行双击事件
table.on('rowDouble(test)', function(obj){
  //obj 同上
});

5.监听行中工具条点击事件

通常你需要在表格的每一行加上 查看编辑删除 这样类似的操作按钮,而 tool 参数就是为此而生,你因此可以非常便捷地实现各种操作功能。tool 参数和 templet 参数的使用方式完全类似**,通常接受的是一个选择器,也可以是一段HTML字符。

table.render({
    cols: [[
        {field:'id', title:'ID', width:100}
        ,{fixed: 'right', width:150, align:'center', toolbar: '#barDemo'} //这里的toolbar值是模板元素的选择器
    ]]
});

//等价于:
<th lay-data="{field:'id', width:100}">ID</th>
<th lay-data="{fixed: 'right', width:150, align:'center', toolbar: '#barDemo'}"></th>

下述是 toolbar 对应的模板,它可以存放在页面的任意位置:

<script type="text/html" id="barDemo">
  <a class="layui-btn layui-btn-xs" lay-event="detail">查看</a>
  <a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
  <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>

  <!-- 这里同样支持 laytpl 语法,如: -->
  {{#  if(d.auth > 2){ }}
    <a class="layui-btn layui-btn-xs" lay-event="check">审核</a>
  {{#  } }}
</script>

//注意:属性 lay-event="" 是模板的关键所在,值可随意定义。

接下来我们可以借助 table模块的工具条事件,完成不同的操作功能:

//监听工具条 
table.on('tool(test)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
    var data = obj.data; //获得当前行数据
    var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
    var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)

    if(layEvent === 'detail'){ //查看
        //do somehing
    } else if(layEvent === 'del'){ //删除
        layer.confirm('真的删除行么', function(index){
        obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
        layer.close(index);
        //向服务端发送删除指令
        });
    } else if(layEvent === 'edit'){ //编辑
        //do something

        //同步更新缓存对应的值
        obj.update({
        username: '123'
        ,title: 'xxx'
        });
    } else if(layEvent === 'LAYTABLE_TIPS'){
        layer.alert('Hi,头部工具栏扩展的右侧图标。');
    }
});

6.监听排序切换

点击表头排序时触发,它通用在基础参数中设置 autoSort: false 时使用,以完成服务端的排序,而不是默认的前端排序。该事件的回调函数返回一个 object 参数,携带的成员如下:

//禁用前端自动排序,以便由服务端直接返回排序好的数据
table.render({
    elem: '#id'
    ,autoSort: false //禁用前端自动排序。注意:该参数为 layui 2.4.4 新增
    //,… //其它参数省略
});

//监听排序事件 
table.on('sort(test)', function(obj){ //注:sort 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
    console.log(obj.field); //当前排序的字段名
    console.log(obj.type); //当前排序类型:desc(降序)、asc(升序)、null(空对象,默认排序)
    console.log(this); //当前排序的 th 对象

    //尽管我们的 table 自带排序功能,但并没有请求服务端。
    //有些时候,你可能需要根据当前排序的字段,重新向服务端发送请求,从而实现服务端排序,如:
    table.reload('idTest', {
        initSort: obj //记录初始排序,如果不设的话,将无法标记表头的排序状态。
        ,where: { //请求参数(注意:这里面的参数可任意定义,并非下面固定的格式)
        field: obj.field //排序字段
        ,order: obj.type //排序方式
        }
    });

    layer.msg('服务端排序。order by '+ obj.field + ' ' + obj.type);
});

五、页面打印

<button type="button" class="layui-btn" id="printpage">打印</button>
$("#printpage").click(function() {
    $(this).hide();
    // window.print()
    document.execCommand('print')
}) 

//定义打印前事件 
var beforePrint = function() {             
    // console.log("beforePrint");           
};       
//定义打印后事件 
var afterPrint = function() {            
    // console.log("afterPrint");             
    $("#printpage").show();            
}

//监听window状态            
if (window.matchMedia) {                
    var mediaQueryList = window.matchMedia('print');            
    //为印添加事件
    mediaQueryList.addListener(function(mql) {                  
        if (mql.matches) {                     
            beforePrint();                  
        } else {                     
            afterPrint();                  
        }                
    });               
}       
//打印前事件
window.onbeforeprint = beforePrint;
//打印后事件
window.onafterprint = afterPrint;   

六、生成随机数

//生成年月日时分秒
function getNowFormatDate() {
    var day = new Date();
    var Year = 0;
    var Month = 0;
    var Day = 0;
    var Hour = 0;
    var Minute = 0;
    var Second = 0;
    var CurrentDate = "";
    Year = day.getFullYear(); //支持IE和火狐浏览器.
    Month = day.getMonth() + 1;
    Day = day.getDate();
    Hour = day.getHours();
    Minute = day.getMinutes();
    Second = day.getSeconds();
    CurrentDate += Year; //CurrentDate =CurrentDate+ Year
    if (Month >= 10) {
        CurrentDate += Month;
    } else {
        CurrentDate += "0" + Month;
    }
    if (Day >= 10) {
        CurrentDate += Day
    } else {
        CurrentDate += "0" + Day;
    }
    CurrentDate = CurrentDate + Hour + Minute + Second;
    return CurrentDate;
}
//后三位随机数
function lastThree() {
    var lastThree = '';
    for (var i = 0; i < 3; i++) {
        lastThree += Math.floor(Math.random() * 10);
    }
    return lastThree
}

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录