示例
基本用法
基本用法、disabled和changed的案例。
- 自动开启快捷键
- editable.disabled 可以控制全表的disabled状态
- editor的disabled配置高于editable.disabled属性
- changed与非super editor功能一致
PCPhonePad
<page>
<actions>
<button
text="{{editable.disabled?'enable':'disabled'}} 全表(除收入)"
bindclick="changeDisable"
></button>
<button text="getData" bindclick="getData"></button>
</actions>
<table
x="table"
type="super"
editable="{{editable}}"
data="{{tableData}}"
bindsort="handleTableSort"
>
<cell name="name" label="姓名" width="120px">
{{cellData.rowData.name}}
</cell>
<cell name="sex" label="性别" width="80px">
<editor
data="{{sex}}"
node="select"
value="{{cellData.rowData.sex}}"
></editor>
</cell>
<cell name="birthDate" label="出生日期" width="130px" sortable>
<editor
value="{{cellData.rowData.birthDate}}"
node="date-picker"
></editor>
</cell>
<cell name="birthTime" label="出生时间" width="130px">
<editor
value="{{cellData.rowData.birthTime}}"
node="time-picker"
></editor>
</cell>
<cell name="workDate" label="入职日期" width="200px">
<editor
value="{{cellData.rowData.workDate}}"
type="daterange"
node="date-picker"
></editor>
</cell>
<cell name="workTime" label="工作时间" width="200px">
<editor
value="{{cellData.rowData.workTime}}"
type="range"
node="time-picker"
></editor>
</cell>
<cell name="favType" label="爱好类型" width="100px">
<editor
value="{{cellData.rowData.favType}}"
node="select"
data="{{favTypeList}}"
bindchanged="favTypeChange"
></editor>
</cell>
<cell name="fav" label="爱好">
<editor
value="{{cellData.rowData.fav}}"
multiple="{{true}}"
node="select"
data="{{cellData.rowData.favList}}"
></editor>
</cell>
<cell name="address" label="住址" width="200px">
<editor
node="cascader"
ajax="{{...cascaderAjax, initData: cellData.rowData.addressInfo}}"
beforeRender="{{beforeCascaderRender}}"
value="{{cellData.rowData.address}}"
/>
</cell>
<cell name="income" label="收入">
<editor
value="{{cellData.rowData.income}}"
node="input"
type="number"
disabled="{{!editable.disabled}}"
suffix="元"
></editor>
</cell>
</table>
</page>
import moment from 'moment';
const traverseNodes = (nodes) =>
nodes.map(({ aggCode, aggName, leaf, childList }) => {
const node = {
label: aggName,
value: aggCode,
leaf, // 标识节点是否为叶子节点,lazyLoad时可标识该节点是否包含子节点
};
if (childList && childList.length) {
node.children = traverseNodes(childList);
}
return node;
});
export default XPage({
data: {
editable: {
disabled: false,
},
favTypeList: [
{
label: '文艺',
value: 1,
items: [
{
label: '唱歌',
value: '2.1',
},
{
label: '画画',
value: '2.2',
},
],
},
{
label: '体育',
value: 2,
items: [
{
label: '网球',
value: '1.1',
},
{
label: '羽毛球',
value: '1.2',
},
],
},
],
sex: [
{
value: '男',
label: '男',
},
{
value: '女',
label: '女',
},
],
tableData: [
{
name: '王大虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1980-1-1',
address: ['AH01', 'Z25', 'Z25-1'],
addressInfo: [
{
value: 'AH01',
label: '大卖场区',
},
{
value: 'Z25',
label: '滨江萧山区',
},
{ value: 'Z25-1', label: '子区域1' },
],
},
{
name: '王二虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1990-1-1',
address: ['AH01', 'Z25', 'Z25-2'],
addressInfo: [
{
value: 'AH01',
label: '大卖场区',
},
{
value: 'Z25',
label: '滨江萧山区',
},
{ value: 'Z25-2', label: '子区域2' },
],
},
{
name: '王三虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '2000-1-1',
},
{
name: '王四虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '2010-1-1',
income: 10,
},
],
cascaderAjax: {
url: '//testapi-nodedmallos.dmall.com/cabinx/pcapi/table/children',
},
},
favTypeChange(value, more) {
if (!value) {
return;
}
const { extraValue, rowData, rowIndex } = more;
const items = extraValue.cur_option[0].items;
rowData.favList = items;
this.getComponent('table').updateEditorData('update', [
{
rowIndex,
data: rowData,
},
]);
},
changeDisable() {
// const disabled = this.data.editable.disabled;
// this.data.editable.disabled = !this.data.editable.disabled
this.setData({
editable: {
disabled: !this.data.editable.disabled,
},
});
},
getData() {
console.info(this.getComponent('table').getData());
},
handleTableSort([{ name, order } = {}]) {
if (!name) {
return;
}
const { data } = this.getComponent('table').getData();
const sortedTableData = [...data];
// 按照出生日期排序
sortedTableData.sort((a, b) => {
const prevBirthDate = moment(a.birthDate).toDate();
const nextBirthDate = moment(b.birthDate).toDate();
// 升序
if (order === 'asc') {
return prevBirthDate - nextBirthDate;
}
// 其他
return nextBirthDate - prevBirthDate;
});
this.setData({
tableData: sortedTableData,
});
},
beforeCascaderRender(res) {
const {
data: { result },
} = res;
/*
*返回的结构
*{ data: Array<{ label: String, value: any, children: Array }>}
*/
return {
data: traverseNodes(result),
};
},
});
校验
- editor 组建的validate属性是一个列表
- 列表元素可以是一个string ,也可以指向组建/页面的方法
- 配置为string 时,代表使用内置的editor ,目前内置的editor 有required
- 可以调用table组建的validateEditors方法,对全表进行校验,全表校验会在遇到第一个错误时终止。
PCPhonePad
<page>
<actions>
<button text="校验表格" bindclick="validateTable"></button>
</actions>
<table type="super" editable="{{true}}" data="{{tableData}}" x="table">
<cell name="fild1" label="fild1(number && 10-20)">
<editor
node="input"
value="{{cellData.rowData.fild1}}"
validate="{{[isNumber, from20to30]}}">
</editor>
</cell>
<cell name="fild2" label="fild2(不为空 && number && 30-40 && fild1不为空)">
<editor
node="input"
value="{{cellData.rowData.fild2}}"
validate="{{['required', fild1IsNotEmpty, isNumber, from40to50]}}">
</editor>
</cell>
</table>
</page>
export default XPage({
data: {
tableData : [
{},{},{},{}
]
},
fild1IsNotEmpty(value, cellInfo, rowData){
if(!rowData.fild1){
return Promise.reject({
text: 'fild1不能为空'
});
}
return Promise.resolve(true);
},
isNumber(value){
if(typeof (value/1) === 'number' && !Number.isNaN(value/1)){
return Promise.resolve(true)
} else {
return Promise.reject({
text: '输入值必须是数字'
})
}
},
from20to30(value){
return new Promise((resolve, reject)=>{
if(value/1>=20 && value/1<=30){
return resolve(true)
}
return reject({
text: '值需要在20到30之间'
})
});
},
from40to50(value){
return new Promise((resolve, reject)=>{
if(value/1>=40 && value/1<=50){
return resolve(true)
}
return reject({
text: '值需要在40到50之间'
})
});
},
validateTable(){
this
.getComponent('table')
.validateEditors((errors)=>{
if(errors && errors.length>0){
CabinX.alert('表格校验有错');
}
});
}
})
行管理器
- 通过在editable 属性添加 rowHandler为true,可以开启编辑表格的添加行列属性
- 当点击添加按钮时,编辑表格会对全表的editor校验是否有primary属性,如果有,则该editor必须有数据
PCPhonePad
<page>
<actions>
<button text="开启/关闭 rowHandler" bindclick="changeRowHandler"></button>
<button text="只允许有收入的开启rowHandler" bindclick="changeIncomeRowHandler"></button>
</actions>
<table type="super"
editable="{{...editable,beforeRowHandlerAdd:beforeRowHandlerAdd,beforeRowHandlerRemove:beforeRowHandlerRemove}}"
data="{{tableData}}" x="table">
<cell name="name" label="姓名">
{{cellData.rowData.name}}
</cell>
<cell name="sex" label="性别">
<editor data="{{sex}}" node="select" value="{{cellData.rowData.sex}}"></editor>
</cell>
<cell name="birthDate" label="出生日期">
<editor value="{{cellData.rowData.birthDate}}" node="date-picker"></editor>
</cell>
<cell name="birthTime" label="出生时间">
<editor value="{{cellData.rowData.birthTime}}" node="time-picker"></editor>
</cell>
<cell name="workDate" label="入职日期(必填)">
<editor value="{{cellData.rowData.workDate}}" type="daterange" node="date-picker" validate="{['required']}"></editor>
</cell>
<cell name="workTime" label="工作时间">
<editor value="{{cellData.rowData.workTime}}" type="range" node="time-picker"></editor>
</cell>
<cell name="favType" label="爱好类型">
<editor value="{{cellData.rowData.favType}}" node="select" data="{{favTypeList}}" bindchanged="favTypeChange"></editor>
</cell>
<cell name="fav" label="爱好">
<editor value="{{cellData.rowData.fav}}" multiple="{{true}}" node="select" data="{{cellData.rowData.favList}}"></editor>
</cell>
<cell name="address" label="住址">
<editor value="{{cellData.rowData.address}}" node="input"></editor>
</cell>
<cell name="income" label="收入(primary)">
<editor primary value="{{cellData.rowData.income}}" node="input" type="number" suffix="元"></editor>
</cell>
</table>
<pop x="addPersonPop" title="添加人员">
<form x="pop-form">
<item node="input" name="name" label="姓名"></item>
</form>
<actions>
<button text="ok" bindclick="addPersonPopConfirm"></button>
<button text="cacnel" bindclick="addPersonPopCancel"></button>
</actions>
</pop>
</page>
export default XPage({
data: {
editable:{
rowHandler:true,
},
favTypeList: [{
label: '文艺',
value: 1,
items: [{
label: '唱歌',
value: '2.1',
},
{
label: '画画',
value: '2.2',
},
],
},
{
label: '体育',
value: 2,
items: [{
label: '网球',
value: '1.1',
},
{
label: '羽毛球',
value: '1.2',
},
],
},
],
sex: [{
value: '男',
label: '男'
}, {
value: '女',
label: '女'
}],
tableData: [{
name: '王大虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1990-1-1',
}, {
name: '王二虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1990-1-1',
}, {
name: '王三虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1990-1-1',
}, {
name: '王四虎',
birthTime: new Date('2021-11-2 08:06:12'),
birthDate: '1990-1-1',
income: 10
}],
},
show(){
},
favTypeChange(value, more){
if(!value){
return;
}
const {extraValue, rowData, rowIndex} = more
const items = extraValue.cur_option[0].items;
rowData.favList = items;
this.getComponent('table').updateEditorData('update',[{
rowIndex,
data:rowData,
}]);
},
changeIncomeRowHandler(data){
this.setData({
"editable.rowHandler": (rowData)=>{
if(rowData.rowData.income/1>0){
return true;
}
return false;
}
});
},
changeRowHandler(){
this.setData({
'editable.rowHandler': !this.data.editable.rowHandler
})
},
addPersonPopConfirm(){
const popForm = this.getComponent('pop-form');
const data = popForm.getData();
this.beforeRowHandlerAddResolve(data)
this.beforeRowHandlerAddResolve = null;
this.beforeRowHandlerAddReject = null;
this.getComponent('addPersonPop').hide();
},
addPersonPopCancel(){
this.beforeRowHandlerAddReject()
this.beforeRowHandlerAddReject = null;
this.beforeRowHandlerAddResolve = null;
this.getComponent('addPersonPop').hide();
},
beforeRowHandlerAdd(){
const that = this;
this.getComponent('addPersonPop').show();
return new Promise((resolve,reject)=>{
that.beforeRowHandlerAddResolve = resolve
that.beforeRowHandlerAddReject = reject;
});
},
beforeRowHandlerRemove(data){
const {rowData, rowIndex} = data;
return new Promise((resolve, reject)=>{
CabinX.confirm({
title:'请确认',
text:`是否要删除 ${rowData.name}?`
},(res)=>{
if(res === true){
return resolve(true)
}else {
return resolve(false)
}
})
});
},
});
Attributes
<table>
支持的属性说明。
Attributes - editable
信息
该属性配置在table 标签上,并且需要table 的type 属性为 super
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
editable | 标识表格的可编辑属性 | boolean/object | true | |
editable.initEmptyRow | 是否在空数据时初始空行 | boolean | true | |
editable.minRowLength | 最小行数 | number | 0 | |
editable.rowHandler | 是否显示行控制列,当类型为function时,用于处理每行是否有添加删除行的控制 | boolean/function | ||
editable.disabled | 控制表格内所有editor是否可编辑,优先级低于editor组建上的disabled属性 | boolean | ||
editable.beforeRowHandlerAdd | 添加行前触发,需要返回promise,如果resolve一个对象,在以这个对象作为新行的渲染数据 | function | ||
editable.beforeRowHandlerRemove | 删除前触发,需要返回promise,resolve boolean值 | function |
Events
名称 | 说明 | 参数 |
---|---|---|
editors-changed | editors的数据修改后触发 | value:{key/index:value}//触发editor修改后的值,more:{rowIndex:行号,colIndex:列号,extraValue:更多值,如select组建的option, rowData:当前行数据} |
<editor>
组件
Attributs
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
node | 指定使用的组建类型 | string | input/select/data-picker/time-picker | input |
placeholder | 在没有指定value时显示的数据 | string | ||
validate | 值校验器 | Array<validatorName:string | customerValidateFunction(value)=>{}:Promise> | required |
disabled | 单元格是否可编辑 | boolean | -- | false |
primary | 是否为主key, 如果设置,将自动添加非空验证,如果开启行控制起(editable.rowHandler) | -- | -- | -- |
trim | 当node=input且type=text(type默认为text)时,去除前后空格字符 | boolean | -- | false |
markInfo | 标记(高亮)信息,MarkInfo为null时,清除当前 editor 标记信息 | MarkInfo | -- | null |
类型 MarkInfo
名称 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
MarkInfo.type | 标记类型 | String | warning/success/info | -- |
MarkInfo.message | 消息内容 | String | -- | '' |
Event
名称 | 说明 | 参数 |
---|---|---|
changed | 当数据修改后触发, | value:{key/index:value}//触发editor修改后的值,more:{rowIndex:行号,colIndex:列号,extraValue:更多值,如select组建的option,rowData:当前行数据} |
支持组件
<editor>
支持的node
组件对应的属性说明
input
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 值 | string | ||
suffix | 后缀 | string |
select
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 值 | string |
date-picker
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 值 | Date/[Date,Date] | ||
type | 时间选择的类型 | string | date/week/year/month/datetime/daterange/datetimerange | date |
time-picker
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 值 | Date/[Date,Date] | ||
type | 时间选择的类型 | string | base/range | base |
Methods
<table>
支持的API。
updateEditorData
更新表格行数据
名称 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
arg1 | 操作类型 | string | add/remove/update | |
arg2 | 更新行信息(普通表格) | {rowIndex:number, data:[{}]} | ||
arg2 | 更新行信息(树形表格) | {rowNum:string, data:[{}]} |
updateEditorsMarkInfo
更新表格的editor的标记(高亮)信息
名称 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
list | 要更新的editor列表标记信息,当为 [] 时清空所有标记,MarkInfo为null时,清除当前 editor 标记信息 | Array<{colName, rowIndex, data: MarkInfo }>/Array<{tdPos: [rowIndex, colIndex], data: MarkInfo }> | -- |
移动端表格 卡片模式 标题和副标题设置
移动端表格渲染支持指定某列 为标题和副标题
如下所示
<x-table>
<x-cell label='列名1' type='title'></x-cell>
<x-cell label='列名2' type='subTitle'></x-cell>
</x-table>
名称 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
type | 指定列为标题或副标题 | string | title/subTitle | -- |