安装与调用
引用下面CSS:
<link rel="stylesheet" href="https://qidian.gtimg.com/lulu/theme/edge/css/common/ui/Table.css"> <link rel="stylesheet" href="https://qidian.gtimg.com/lulu/theme/edge/css/common/comp/Table.css">
JS为:
<script type="module" src="https://unpkg.com/lu2/theme/edge/js/common/comp/Table.js"></script>
或者:
<script type="module"> import "https://unpkg.com/lu2/theme/edge/js/common/comp/Table.js"; </script>
本组件为内置自定义元素组件,如果需要兼容Safari浏览器,还需要引入下面的JS。
<script src="https://unpkg.com/lu2/theme/edge/js/common/safari-polyfill.js"></script>
由于此Polyfill执行了querySelectorAll匹配,因此Safari浏览器下,组件connetedCallback生命周期函数的执行时机比Chrome/Firefox浏览器靠后,因此,如果要兼容Safari浏览器,在执行参数设置的时候,可以在当前表格元素的DOMContentLoaded或connected回调中设置。详见本文档源代码。
如果是npm安装调用,则:
import 'lu2/theme/edge/css/common/ui/Table.css'; import 'lu2/theme/edge/css/common/comp/Table.css'; import 'lu2/theme/edge/js/common/safari-polyfill.js'; import 'lu2/theme/edge/js/common/ui/Table.js';
如果 JS import语法报错,试试在业务代码中动态引入。
import('lu2/theme/edge/js/common/safari-polyfill.js'); import('lu2/theme/edge/js/common/ui/Table.js');
使用is="ui-table"
本组件为动态列表解决方案,如果是静态列表,请访问“布局 » Table表格”。
本组件为Web Components组件,通过对原生<table>
元素进行扩展实现。
使用方法很简单,给<table>
元素设置is="ui-table"
即可。
配合特定的HTML元素和参数,无需任何初始化,即可实现带交互的动态表格效果。
<table is="ui-table"></table>
内置的交互逻辑包括:
- 数据请求
- 模板渲染
- loading
- 为空或出错提示
- 分页
- 分页数量设置
- 全选反选
- 表单筛选
1. 数据请求
列表数据请求的接口和参数可以使用以下方法设置:
- 【推荐】使用关联form元素,这个可以参见后面的“综合交互案例演示”。
- 在
<table>
元素上通过data-url
属性指定请求的URL地址和参数。 设置参数。
table.setParams({ ajax: { url: '', data: {} } });
此参数为全局设置,任何请求都会使用这些参数。
table.ajax()
方法也可以传递参数(同时请求新的数据),此参数则为临时参数。例如:table.ajax({ url: '', data: {} });
2. 模板渲染
本组件内置一套模板渲染规则。
列表渲染的模板使用HTML5 <template>
元素,模板语法为原生的ES6的模板字符串语法,非常容易上手。
模板语法仅支持表达式,并不支持if...else
这类逻辑语句块,因此如果有逻辑判断,可以使用3元表达式实现。
${ flag ? `<ele-a>` : `<ele-b>` }
使用的时候,可以把<template>
元素设置在<tbody>
元素中,本组件会自动识别该模板元素。
当然,您也可以使用自定义的模板渲染语法,或者自己拼接字符串,通过以下方法设置:
table.params.parse = function (json) {
// json就是后台返回的JSON数据
// return的字符串内容会作为<tbody>
元素的innerHTML
};
模板中的字符串内容可以使用下面代码获取:
table.params.template
3. loading
当数据请求发生的时候,本组件会显示loading效果,这个loading效果是<ui-loading>
元素实现的。
如果列表上下文中没有<ui-loading>
元素,本组件会自动创建,但是这样可能会出现页面布局突然变化的不好的体验,因此建议使用<ui-loading>
元素进行占位,位置放在<table>
元素的后面。
<div class="table-x"> <table is="ui-table"></table> <ui-loading rows="15"></ui-loading>
当分页切换的时候,本组件会自动控制loading元素的显示与隐藏,以及尺寸大小。
loading元素可以使用下面代码获取:
table.element.loading
4. 为空或出错提示
本组件在请求没有数据或者出错的时候,会自动出现提示信息,默认是高度300px同时水平垂直居中的文字提示效果,效果如下所示:
文章标题 |
---|
相关代码如下:
<div class="table-x"> <table is="ui-table"><thead><tr><th>文章标题</th></tr></thead></table> <div class="table-null-x" style="display: flex;">暂无数据</div> </div>
通常情况下,我们无需关心出错提示的细节信息,但是,如果希望出错提示是非常精致的,例如有图标,则大家就可以提前写好出错提示信息,本组件会在出错或无数据时候自动显示。
其中,无数据提示的容器元素需要类名是table-null-x
,出错提示的的容器元素需要类名是table-error-x
。
在“综合交互案例演示”那里有相关示意。
为空元素和出错提示元素可以使用下面代码获取:
table.element.empty; table.element.error
5. 分页
分页是可选的,如果不设置,列表是不会显示分页的。
分页使用<ui-pagination>
元素,位置任意,只要其祖先元素和<table>
元素的父元素保持一致即可。
例如:
<div class="table-x"> <table is="ui-table"></table> <ui-pagination per="10"></ui-pagination> </div>
如果列表中默认没有<ui-pagination>
元素,则本组件会寻找类名为table-page
的元素,并在其中创建<ui-pagination>
元素。这个在“综合交互案例演示”那里有相关示意。
分页元素可以使用下面代码获取:
table.element.pagination
本组件分页的总数需要后端反馈,也就是请求列表JSON数据的时候需要包含数据总量字段,默认是total
,可以替换成其他。
下面是本组件支持的分页总数数据结构:
{
"error": 0, // 或者"code": 0
"total": 50,
}
或者:
{
"error": 0, // 或者"code": 0
"data": {
"total": 50,
"data": []
}
}
这样,本组件才能准确分页。以及,每次请求完毕,匹配选择器output[data-type="total"]
的元素的内容都会变成分页总数的值。
6. 分页数量设置
分页数量设置也是可选的。
分页数量设置使用<ui-drop>
元素,同时需要设置data-type="per"
,避免和其他<ui-drop>
元素冲突。
默认情况下,分页数量可以设置为[15, 30, 50]
这3档,想要修改分页数量,可以使用下面的代码:
table.params.list = [10, 15, 20, 30];
例如下面的实时效果,点击数字可以看到列表项,页面刷新的时候会记住上一次的选择:
这个案例演示代码如下(表格隐藏了):
<table id="tableDrop" is="ui-table" hidden></table> <ui-drop data-type="per">15</ui-drop>
分页数量下拉元素可以使用下面代码获取:
table.element.drop
7. 全选反选
本组件集成了全选反选功能,可以实现批量操作。
其中,复选框一定要设置在第一个<td>
、<th>
元素中,以及可以设置类名table-checkbox
,对排版进行了一定的优化,代码示意:
<div class="table-x table-checkbox"> <table is="ui-table"></table> </div>
每次有复选框元素选中/取消选中行为发生的时候,都会触发自定义的'check'
事件,例如:
table.addEventListener('check', function (event) {
// 复选框点击会执行这里代码
let detail = event.detail;
});
其中detail
对象包含下面这些参数:
{ isAllChecked: true/false, isAllUnchecked: true/false, target: eleCheckbox, allEnabledCheckbox: [eleA, eleB, ...] }
具体含义如下:
- isAllChecked
- 布尔值。表示是否全部选中。
- isAllUnchecked
- 布尔值。表示是否全部未选中。
- target
- 元素对象。表示当前点击的复选框元素。
- 数组。表示列表中所有非禁用态的复选框元素。此参数在批量处理的时候很有用。
8. 表单筛选
这是本组件比较强大且重要的功能。
本组件对<table>
元素扩展了一个form
属性,是的<table>
元素可以和<input/button>
等元素一样,直接table.form
就可以返回关联的<form>
元素。
在实际开发者,复杂列表一定是和表单相关联的,例如搜索功能。
在LuLu UI的体系下,你无需任何其他额外的JS设置,就可以完成和列表联动的搜索能力。
关键点就是使用这里的form
属性,把<table>
元素的form
属性值设置为对应的<form>
元素的id
值即可。例如:
<form id="myForm" action="/get"> <input type="search" name="key"> </form> <table is="ui-table" form="myForm"></table>
此时,<form>
元素的action
地址就是接口请求的地址,<form>
元素中的表单控件数据也会作为请求参数一起发送过去。
例如,上面的HTML代码,最终的请求地址一定包含下面这部分:
/get?key=xxx
如果有分页,还会自动包含分页相关数据。
<form>
元素自动内置了表单验证行为,当触发submit
提交行为的时候,列表也会重新加载。
可以使用下面的代码自定义的表单验证行为:
// 语法详见Validate.js
this.params.form.validate = [];
如果表单提交触发列表加载的时候希望传递额外的参数,可以:
this.params.form.data = { key: 'value' };
需要注意的是上面的参数在点击分页切换的时候是不会添加的,如果任意请求都需要传递某些参数,请使用下面的语法:
eleTable.params.ajax.data = { key: 'value' }
纯展示案例演示
接下来演示的是简单的静态展示列表效果,无需任何额外的JavaScript代码进行初始化。
文章标题 | 发布时间 | 评论数 |
---|---|---|
${obj.title} | ${obj.time} | ${obj.comment} |
完整的HTML代码如下所示(注意:.table-x 类名是必须的):
<div class="table-x"> <table is="ui-table" data-url="/get"> <thead> <tr> <th>文章标题</th> <th width="22%">发布时间</th> <th width="15%">评论数</th> </tr> </thead> <tbody> <!-- 模板 --> <template> ${ data.data.map(obj => { return `<tr> <td>${obj.title}</div></td> <td>${obj.time}</td> <td>${obj.comment}</td> </tr>` }).join('') } </template> </tbody> </table> <!-- 加载loading --> <ui-loading rows="15"></ui-loading> <!-- 分页,每页10项 --> <ui-pagination per="10"></ui-pagination> </div>
在本演示中,就是使用的data-url
属性指定Ajax数据拉取的URL地址。
分页的交互行为组件内置,使用的时候无需关心细节。
综合交互案例演示
本案例演示重点在分页与列表交互,复选框选中与列表交互,列表中动态内容的事件处理,以及外部的搜索、删除如何影响列表的显示。
文章标题 | 发布时间 | 评论数 | ||
---|---|---|---|---|
${obj.title} | ${obj.time} | ${obj.comment} | ${index ? `` : ``} |
文章列表为空
系统将在用户删除文章一个工作日后,
自动彻底清理
代码
1. HTML代码
只要按照提供的特定的HTML结构书写,无需任何额外的JavaScript代码设置,列表就能正常显示。
完整HTML如下所示,包括模板、关联表单、无数据、分页、分页数量设置、loading等:
<!-- 注意,此表单也是组件功能一部分 --> <form id="mixForm" action="/search"> <div class="table-search ui-input ui-input-search" align="end"> <input type="search" name="key" placeholder="搜error出错,其他随机" required> <button type="submit" class="ui-icon-search">搜索</button> </div> </form> <a id="btnDelComment" title="演示返回数据为空的效果" is-tips><i class="icon_del"></i>删除文章</a> <!-- 列表部分 --> <div class="table-x table-checkbox"> <table id="tableMix" is="ui-table" form="mixForm"> <thead> <tr> <th><input type="checkbox" is="ui-checkbox"></th> <th>文章标题</th> <th width="22%">发布时间</th> <th width="15%" class="tr">评论数</th> <th width="15%" class="tc"> </th> </tr> </thead> <tbody> <template> ${ data.data.map((obj, index) => { return `<tr> <td><input type="checkbox" is="ui-checkbox"></div></td> <td>${obj.title}</div></td> <td>${obj.time}</td> <td>${obj.comment}</td> <td>${index ? `<a href="javascript:;" class="icon icon_del ui-tips" title="删除评论"></a>` : `<input type="checkbox" id="switch" is="ui-checkbox">`}</div></td> </tr>` }).join('') } </template> </tbody> </table> <!-- 列表无数据的占位-可选 --> <div class="table-null-x"> <img src="delete.png"> <h4>文章列表为空</h4> <p>系统将在用户删除文章一个工作日后,<br>自动彻底清理</p> </div> <!-- 列表加载loading --> <ui-loading rows="15"></ui-loading> <!-- 底部分页 --> <div class="table-page-x"> <div class="table-page-data"> 共<output class="table-page-total" data-type="total">0</output>篇文章, 每页显示<ui-drop class="table-page-per" data-type="per">15</ui-drop> </div> <!-- 这里面会显示分页 --> <div class="table-page"></div> </div> </div>
如果对文案和样式没有特别高的要求,“列表无数据的占位”元素.table-null-x
可以删除,到时候会显示“暂无数据”。
如果你对样式要求不高,但对文案有要求,可以下面这样:
<div class="table-null-x" style="dislay:none;">这里是你的文案</div>
2. 与交互行为相关的JS代码
列表中的事件和行为需要开发者自己绑定,当然,这里的列表解决方案也提供了一些可使用的自定义事件,例如下面代码中出现的'check'
事件。
// 列表综合实例交互代码示意 var eleBtnDelete = document.getElementById('btnDelComment'); var eleTable = document.getElementById('tableMix'); // 列表中单复选框选中后的状态处理 eleTable.addEventListener('check', function (event) { let detail = event.detail; if (detail.isAllUnchecked) { eleBtnDelete.removeAttribute('href'); } else { eleBtnDelete.setAttribute('href', 'javascript:'); } }); // 列表删除事件演示 // 需要走委托才行 eleTable.addEventListener('click', function (event) { if (event.target.matches('a.icon_del')) { new Dialog().confirm('确认删除该评论?'); } }); // 删除全部评论 eleBtnDelete.addEventListener('click', function () { if (!this.hasAttribute('href')) { return; } new Dialog().confirm('确认删除选中的这些评论?', { buttons: [{ value: '删除', events: function (event) { eleTable.ajax({ data: { action: 'empty' }, success: function () { eleBtnDelete.removeAttribute('href'); } }); event.dialog.remove(); } }, {}] }); }); // 如果表单提交触发的分页内容更新希望添加额外的查询字段,可以使用下面语法 eleTable.params.form.data = { type: 'submit' }; // 下面代码示意的是搜索内容有值,新增一个action查询字段 // 这个逻辑是方便测试用的,实际开发不需要这个,后台可以判定 eleTable.form.addEventListener('input', function () { if (!eleTable.params.ajax.data) { eleTable.params.ajax.data = {}; } if (this.querySelector('input[type="search"]').value.trim()) { eleTable.params.ajax.data.action = 'search'; } else { delete eleTable.params.ajax.data.action; } });
语法和参数
已知:
let myTable = document.querySelector('table[is="ui-table"]');
则所有的参数设置均围绕myTable
展开。
myTable
暴露了以下属性和方法:
{ element: { // 分页下拉元素,可能不存在 drop: null, // 分页元素,可能不存在 pagination: null, // 分别是:为空提示元素,loading元素,出错提示元素 loading: null, empty: null, error: null, }, params: { // 分页数据 page: {}, // 请求数据 ajax: {}, // 表单数据 form: {}, // 分页数列表数据 list: [] }, // 参数设置 setParams: (options) => {}, // 刷新列表 ajax: (options) => {} }
其中,myTable.element
只读,myTable.params
可读写,相关参数具体语法如下:
参数
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
ajax | Object | {} | Ajax请求参数。支持下面这些参数。
|
page | Object | {/*见释义*/} | 分页相关的一些参数。
默认值如下: { // 总数据量 total: 0, // 每页数目 per: 15, // 当前页数 current: 1 // 接口映射关系 keyMap: { key: '', total: 'total', per: 'per', current: 'current' } }参数 keyMap 用来指定LuLu UI分页字段和后端分页字段的映射关系,例如后端返回分页信息如下:{ "code": 0, "data": { "page 则此时,keyMap参数设定为: keyMap: { key: 'page 可以看出参数 |
form | Object | {} | Form表单请求和验证参数。
|
list | Array | [15, |
分页下拉的列表数据。 |
parse | Func |
{/*见释义*/} | 对Ajax返回的数据进行解析,并返回对应列表的HTML字符串,如果没有数据,返回空字符串。 支持一个参数,为后端返回的最原始的JSON数据对象。 默认值如下: (json) => { if (this.params.template) { return this.params.template.interpolate(json); } return ''; } 本组件对所有字符串扩展了一个名为 |
参数设置有如下方法:
- 直接设置,例如:
myTable.params.parse = otherFun; myTable.params.ajax.url = '/someUrl';
- 使用
setParams()
方法,例如:myTable.setParams({ parse: otherFun, ajax: { url: '/someUrl' } });
如果参数设置完毕,希望列表立即刷新,可以执行ajax()
方法,例如:
myTable.ajax();
ajax()
方法支持一个可选参数,表示请求的参数,参数类型同myTable.params.ajax
,这里不在赘述,例如:
myTable.ajax({ data: { key: 'newValue', success: function () { console.log('请求成功'); } } });
myTable还支持如下两个自定义事件。
事件名称 | 释义 |
---|---|
DOMContent |
当表格元素初始化完毕的时候执行。 |
connected | 当自定义表格元素和页面建立连接的时候执行。 |
本页贡献者:
zhangxinxu