组件
不同于我们常用的Element组件库,示例和代码都在一起,方便直接进行示例代码的复制粘贴。
v8pro的组件示例见示例,示例代码见模块-example示例,我们可以在示例代码中点击运行查看对应的组件效果。
1.布局组件
- viewport 类比为 div ,可以通过设置layout属性调整其内部元素的布局(是一个全屏的盒子,页面上所有的元素必须为他的子级,否则展示不出来;但弹窗可以使用array组件与viewport平级 下 放 window组件)
-
pannel layout设置为row 内部表单元素会按照inline方式进行布局
-
container 容器组件,比如页面需要加载另一个组件,需要一个container容器
-
card
以上几个没看出有啥区别
2.表单组件
-
- 没有专门的form组件,通常使用pannel进行包裹各表单项,进行表单项的布局,比如水平,垂直或inline
-
- 表单校验,示例:
if (Wb.verify(app.viewport1)) {
Wb.ajax({
url: xpath + '&xaction=save',
comps: app.viewport1,
success() {
Wb.tipDone();
}
});
}
通常框架会自动进行校验。
-
3.required ,tip ,validator 等都可以在属性中定义
-
4.ajax提交数据时,可以直接通过下面方式获取表单数据
Wb.getValue(app.viewport1) //会收集所有含有value的键值对,比如{userName:'admin'}
app.Cid.getValue() //获取某个组件实例的value值。 注意:cid必须是唯一的,比如页面的查询项和弹窗中的表单项不能取相同的cid,否则无法获取到值
Wb.apply({},Wb.getValue(app.viewport1)) // apply对象的合并
- 5.表单重置
Wb.reset(app.panel1)
- 6.表单项的laelWidth可以设置宽度,保证label对齐,避免有些项加了required,有些没加不对齐的情况;hint可以设置提示
3.表格组件grid
-
1.表格如果需要mock数据,可以在grid组件中配置localData的值;若配置了localData则不会发送ajax请求到后端
-
2.服务端渲染的表格 可以 url 链接到对应的代码 ;设置了autoLoad为true则初始化就会调用url服务
- 3.增删改查后更新表格数据
app.grid1.reload() //会自动调用后端查询接口,默认使用最后一次load方法的参数
不同于 app.grid1.load()//会初始化所有查询参数
- 4.带操作的表格列如果想要生效一定要把array组件的cid改成buttons;一定要把array组件的cid改成columns,否则内容不展示
- 5.grid的toolbar组件如果要展示,必须设置isProperty属性为true,否则会当成表格内容进行渲染,加了后才会向下面这样渲染
- 6.column必须设置的属性 fieldName 相当于element的prop,对应后端返回的字段名称
- 7.text可以设置列标题,width可以设置列宽度,align属性只能设置表体单元格的居中,表头的居中需要配置titleAlign属性,render属性可以通过js自定义单元格HTML的输出
render示例一:根据不同状态设置单元格为不同的tag
//value可以直接获取单元格的值
if(value == '0'){
let a = el.addEl('w-ta-center0', 'div');
let b = a.addEl('w-tb-center0', 'div');
b.textContent = '关闭';
} else if(value == '1'){
let a = el.addEl('w-ta-center1', 'div');
let b = a.addEl('w-tb-center1', 'div');
b.textContent = '存续';
}
render示例二 :将单元格的内容渲染为html
//this.data可以获取该行的数据
let pTag = el.addEl('my-link','div')
pTag.innerHTML = this.data.privateStatute
-
8.设置editable属性为true可以设置表格为可编辑,可编辑表格必须作为对应的column设置editor属性,如果未设置editor属性那么该列仍然不可编辑。
-
9.可编辑表格,编辑项是select下拉列表会存在鼠标移出单元格是undefined的情况,需要在当前列表的render函数中返回一个数组或者处理成字符串也可以
//初始化回显时,返回的是字符串,可以直接显示;当用户页面选择时,value值是数组对象,需要处理,否则显示为[object,object]
if(Wb.isArray(value)){
// return value.map(item=>item.text)
return value.map(item=>item.text).join(',')
}
return value
- 10.当回显时该单元格实际返回一个字符串,也会出现鼠标聚焦该编辑项时undefined的情况。因为value和下拉select实际存的option不一致,也需要处理
解决方案如下:
console.log('value---', this.value) //初始化回显时value格式如:['开发者,baoweifang']
console.log('data---', this.data)
let item = this.value[0]
if (typeof item === 'string') {
let transValue = item?.split(',') ?? [] //格式转换成:['开发者','baoweifang']
if (transValue.length && typeof transValue[0] === 'string') {
const selectedOptions = this.data.filter(item => transValue.includes(item.text))
this.value = selectedOptions
}
}
- 11.表格添加行
app.editableGrid.addRecord();
- 12.grid的操作列的按钮中 ready事件这样写可以设置按钮的隐藏或禁用
this.setVisible (false) // 隐藏
this.setDisabled (false) // 禁用
按照上述方式,可以避免在actionCol中写一堆动态添加元素和移除元素的逻辑,像下面这样的:
const PROJECT_STATUS = this.data.PROJECT_STATUS
let row = this;
function addClaimBtn(el) {
row.addFooter({
cname: 'button', returnType: 'int', text: "认领", width: '5em', type: "primary",
events: {
click(event) {
handleClaim()
}
}
}, el);
}
//已发布状态才可以认领
if(PROJECT_STATUS === '1'){
const wrap = createBtnWrap()
addClaimBtn(wrap)
}else{
row.removeAll(1)
}
- 13.表格配置多选
获取多选数据时,直接在点击按钮时进行数据的过滤。
- 14.实操中常用的属性
- data 获取显示的数据,和element-ui一致。
注意:如果要实现页面的响应式更新,需要替换一个数组,单纯的调用数组的变异方法是不生效的,这点有别与vue的列表渲染
示例:
function handleConfirm(){
Wb.request({
url:xpath + '&xaction=post',
params:Wb.getValue(app.modalWin),
success(res){
const addedData = Wb.getValue(app.modalWin)
// app.grid1.data.push(addedData) //不会触发页面更新
// app.grid1.reload() // 这个方法也不会
app.grid1.data = [...app.grid1.data,addedData] // ok
Wb.tipSucc('添加成功')
app.modalWin.close()
}
})
}
handleConfirm()
- selection 当前选中行实例,selection.data获取对应行的数据,等同与下面的selectionData
- selectionData 获取当前选中的行数据
- selections/selectionsData 是数组类型,但是如果没有选中行,是空数组,而非全部
- originData 也可以获取当前选中的行数据,不知道和selectionData有啥区别
app.grid1.selections
app.grid1.selectionData
app.grid1.originData
Wb.getActionHint(recs, 'id') //获取选中数据的唯一标识,调用getActionHint方法进行二次确认
delRecords 删除行,直接删掉了,无需刷新列表;但实际并没有重新计算分页,所以建议删除后还是调用app.grid1.reload()
4.弹窗组件
- 1.使用的是window组件,设置弹窗的标题是title属性,记住不能设置text,text代表的是body里面的内容,如果设置了text,则下面的子元素会不显示。
- 2.打开关闭弹窗
```js
app.autoResetWin.show();
app.autoResetWin.close();
```
- 3.如果在关闭之前需要执行一定操作,需要配置closeAction为destory,同时添加destory事件
- 4.新增和编辑时打开弹窗,示例
function handleEdit(){
const selectedData = app.grid1.selectionData
if (!selectedData){
Wb.warn('请选择一条数据')
returnset
}
app.modalWin.show()
Wb.setValue(app.modalWin,selectedData)//数据回显
app.modalWin.title="编辑"
}
handleEdit()
注意:弹窗里面的表单元素的cid建议与表格里面column的fieldName一致,方便直接解构。如果不一致,setValue的第二个参数中的键名需要与表单的cid一致,因为setValue方法是把值按键名对应组件cid进行赋值的。
var sels = app.grid1.selectionData;
console.log(sels);
if (sels == undefined) {
Wb.warn('请选择一条数据');
return;
}else{
app.deptEditWin.show();
Wb.setValue(app.deptEditWin,{
USER_NAME_edit:sels.USER_NAME,
DISPLAY_NAME_edit:sels.DISPLAY_NAME
});
app.deptEditWin.title = '修改';
}
setValue方法说明如下:
- 5.弹窗确定事件,比如保存表单数据,关闭弹窗,刷新列表数据
需要设置弹窗的ok事件,示例代码见上面 handleConfirm
-
6.新增和编辑共用一个弹窗
- 6.1可以通过给app赋值一个变量,比如app.isEdit ,该变量只在当前页面生效
- 6.2新增时清空编辑的数据,数据的值需要和组件的数据一致,统一给undefined并不生效,比如我用的是input和textarea,给空字符串是可以的,示例如下:
const params = Wb.getValue(app.draftModal) for(let key of Object.keys(params)){ params[key] = "" } Wb.setValue(app.draftModal,params) app.draftModal.show() app.isEdit = false app.draftModal.title = "新增底稿"
注意: NO!可以直接设置resetDialog后则每次打开弹窗都会重置,新增时可以无需清空数据,减少一步操作。是不是更方便啦!
BUT:resetDialog只会重置表单元素数据,如果打开的弹窗里面还有其他类型组件,比如文本或表格等,需要在colse事件中清空下。避免数据未请求回来时是上一个列表对应的数据。
如果需要在关闭弹窗时执行保存事件,不应使用close事件,而应使用hide事件。close事件会把数据重置为初始值。
7.设置弹窗的defaults属性,可以使所有的子表单元素组件的labelWidth进行统一;这样可以避免给表单的每一项设置labelWidth
8.如果不需要展示弹窗底部的取消,确定按钮,可以去掉dialog:true的配置或者改成false即可.如果配置了resetDialog,也需要去掉
5.tree和select
- 1.数据来源于接口,只需要配置url属性即可
- 2.可以在success事件中对请求回来的数据做处理,比如
let newArr = response[0].children
newArr.forEach(item => {
addLeafProperty(item)
})
app.deptTree.setData(response)
function addLeafProperty(node) {
node._leaf = node.children.length === 0;
node._expanded = true;
node._disabled = node.children.length > 0 ;
if (node.children.length > 0) {
for (let child of node.children) {
addLeafProperty(child);
}
}
}
注意:框架目前如果父级设置了_disabled为true,即使子级_disabled为false,子级也会被禁用。可以在beforeSelect中阻止对应节点的选中
if (!item.leaf) {
Wb.tip('Please select a leaf node');
return false;
}
-
3.需要手动加上leaf属性,才会展示会文件形式,否则都是文件夹目录
-
4.subTextField可以设置副文本,值为后端对应的字段名称
5.treeSelect只有设置了treePicker {itemsPath:'children'}子级才会正确展示,itemsPath为子级展示的后端字段名称
6.tree组件的子节点字段是items不是children,在扁平化app.deptTree.data时需要注意
7.treeSelect 如果想要正确回显,需要同时设置该组件的textField和valueField值,默认读取的是text和value.
示例代码:
let rec = app.deptTree.selectionData
app.deptEditWin.show();
app.deptEditWin.title = '修改'
app.PARENT_ADD.visible = false
app.PARENT.visible = true
app.CODE.setDisabled(true)
Wb.setValue(app.deptEditWin,rec)
Wb.setValue(app.deptEditWin,{NAME:rec.NAME,CODE:rec.CODE,PARENT:rec.PARENT_ID});
app.PARENT.value = {
NAME:rec.PARENT_NAME,
ID:rec.PARENT_ID
}
//如果选中的是第一级,清空弹窗中父级的展示,避免展示'0'
if(app.deptTree.selectionData?.PARENT_ID == '0'){
Wb.setValue(app.deptEditWin, { PARENT:'' })
}
app.isEdit = true;
8.treeSelect如果需要加请求参数,可以在beforeload事件中这样写
params.foo = 'bar';
9.select下拉框如果想要同时获取选中选项的label和value值,可以设置bindField,且bindFied的值会自动传给后端,无需处理参数。比如设置bindFied为DEPT_NO,则{DEPT_NO:ID}会传给后端,DEPT_NAME会绑定textField的值传给后端
传给后端的参数{DEPT_NO:ID,DEPT_NAME:NAME}。如果不设置默认给后端传递的参数只有{DEPT_NAME:ID}
10.select如果设置多选,multiSelect:true。cid绑定的值默认为数组,且包含text和value,类似 [{text:'bwf',value:1},{text:'wmy',value:2}],如果要正确回显,对应的字段也必须保持一致的数据格式。所以在入参时需要进行拆分,回显时进行组合拼接。 配置如下:
编辑时确认参数拆分:
if(params.GROUP_MEMBERS && params.GROUP_MEMBERS.length){
const members = [...params.GROUP_MEMBERS]
params.GROUP_MEMBERS = members.map(item=>item.EMP_NAME).join(',')
params.GROUP_MEMBERS_NO = members.map(item=>item.EMP_NO).join(',')
}else{
params.GROUP_MEMBERS = null
}
回显时将字段进行合并
let GROUP_MEMBERS = selectionData.GROUP_MEMBERS
if (GROUP_MEMBERS && GROUP_MEMBERS.length) {
const GROUP_MEMBERS_NAME = selectionData.GROUP_MEMBERS.split(',')
const GROUP_MEMBERS_NO = selectionData.GROUP_MEMBERS_NO.split(',')
GROUP_MEMBERS = GROUP_MEMBERS_NAME.map((item, index) => {
return {
EMP_NAME: GROUP_MEMBERS_NAME[index],
EMP_NO: GROUP_MEMBERS_NO[index]
}
})
}
//设置组员的回显
Wb.setValue(app.GROUP_MEMBERS, { GROUP_MEMBERS })
10.多选时设置required属性时,即使已经选择了值,但还是会校验不通过,建议在提交时做校验。
数据请求
-
Wb.ajax
-
Wb.request
-
Wb.Request.ajax
常用的serveScript
建表语句
CREATE TABLE IF NOT EXISTS bwf_user (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
这个语句创建了一个名为users的表,包含以下字段:
id: 主键,自动递增。
username: 一个最大长度为50个字符的字符串,不能为空。
password: 一个最大长度为50个字符的字符串,不能为空。
email: 一个最大长度为100个字符的字符串。
created_at: 时间戳,默认为当前时间。
IF NOT EXISTS是可选的,用来避免在表已经存在的情况下重复创建。
1.增,在xwl文件的serveScript中写下面代码
//后端
方式1,执行sql语句,参数使用{?USERNAME?}的方式
Wb.sql(`insert into bwf_user (USERNAME,PASSWORD,EMAIL) values ({?USERNAME?},{?PASSWORD?},{?EMAIL?})`)
方式2,
Wb.sendRowx(`insert into bwf_user (USERNAME,PASSWORD,EMAIL) values ({?USERNAME?},{?PASSWORD?},{?EMAIL?})`)
方式3,
//const ID = Wb.getId() //新增时不需要传入ID,系统会自动生成ID;传入时还会有重复的出错提示
const USERNAME = Wb.get('USERNAME')
const PASSWORD = Wb.get('PASSWORD')
const EMAIL = Wb.get('EMAIL')
Wb.sync({ tableName: 'bwf_user', insert: { USERNAME:USERNAME,PASSWORD:PASSWORD, EMAIL:EMAIL},send:true});
注意:只有sql语句可以通过{?USERNAME?}获取前端传递的参数,名称一致;sync时需要通过Wb.get('USERNAME')的方式手动获取参数
//前端
//1.打开弹窗
app.addModal.show()
app.addModal.title = '新增'
//2.弹窗ok确认事件
let params = {
USERNAME:app.USERNAME_add.getValue(),
PASSWORD:app.PASSWORD_add.getValue(),
EMAIL:app.EMAIL_add.getValue(),
}
Wb.request({
url:xpath+'/insert',
params,
success() {
Wb.info('新增成功!');
app.addModal.close();
app.grid1.reload();
}
})
2.删
//方式1,
const userData = Wb.sql(
{
sql: `
delete from
bwf_user
where ID = {?ID?}`,
}
);
Wb.send(userData) //发送数据给客户端,必须加,否则只是数据库加了,页面不会立马展示
//方式2
Wb.sendRowx('delete bwf_user where ID ={?ID?}')
TODO:sync方式实验没有成功,报错 TypeError: e.getMessage is not a function
Wb.sync({
tableName: 'bwf_user',
del:{
ID:Wb.get('ID')
},
whereFields:"ID"
})
//前端
function handleDel(){
let grid = app.grid1, recs = grid.selections;
if (!recs.length) {
Wb.tipSelect();
return;
}
Wb.confirm(Wb.getActionHint(recs, 'ID'), f => {
Wb.ajax({
url: xpath+'/del',
params: { ID: app.grid1.selectionData.ID},
success() {
Wb.info('success')
grid.delRecords(); //纯前端删除选中的行,实际不会删除数据库中的数据;不会重新计算分页
// app.grid1.reload() //会发送请求
}
});
});
}
handleDel()
3.改
//后端
//方式1
Wb.sendRowx('update bwf_user set USERNAME={?USERNAME?},PASSWORD={?PASSWORD?} ,EMAIL={?EMAIL?} where ID ={?ID?}')
//方式2
Wb.sql('update bwf_user set USERNAME={?USERNAME?},PASSWORD={?PASSWORD?} ,EMAIL={?EMAIL?} where ID ={?ID?}')
//方式3
const ID = Wb.get('ID')
const USERNAME = Wb.get('USERNAME')
const PASSWORD = Wb.get('PASSWORD')
const EMAIL = Wb.get('EMAIL')
//报错 TypeError: e.getMessage is not a function
Wb.sync({ tableName: 'bwf_user', update: {ID, USERNAME,PASSWORD, EMAIL},whereFields:'ID',send:true});
//前端
//1.打开弹
function handleEdit(){
const selectedData = app.grid1.selectionData
if (!selectedData){
Wb.warn('请选择一条数据')
return
}
app.editModal.show()
Wb.setValue(app.editModal,{
USERNAME_edit:selectedData.USERNAME,
PASSWORD_edit:selectedData.PASSWORD,
EMAIL_edit:selectedData.EMAIL
})
app.editModal.title="编辑"
}
handleEdit()
//2.弹窗点击确定ok事件
let params = {
ID:app.grid1.selectionData.ID,
USERNAME:app.USERNAME_edit.getValue(),
PASSWORD:app.PASSWORD_edit.getValue(),
EMAIL:app.EMAIL_edit.getValue(),
}
Wb.request({
url:xpath+'/update',
params,
success() {
Wb.info('修改成功!');
app.editModal.close();
app.grid1.reload();
}
})
4.查,注意条件要加下null,否则初始化查询没有数据
//后端:
//方式1:USER_NAME 变量为调用load方法传过来的
Wb.sendRowx(`select * from bwf_user where {?USERNAME?} is null or USERNAME = {?USERNAME?}`)
//方式2:
var userData = Wb.sql(
{
sql: `
select * from
bwf_user
where {?USERNAME?} is null or username = {?USERNAME?}`,
}
);
Wb.send(userData) //发送数据给客户端
//前端:
const USERNAME = app.USERNAME.getValue();
app.grid1.load({
params:{
USERNAME
}
})
组件化与模块化
common.js
AMD
CMD
esmodule
1.页面中如何引入一个组件,示例,下面是一个按钮的点击事件
let ct = app.runModulePanelCt; //runModulePanelCt 是页面的容器组件
ct.destroyAll();
Wb.run({
url: 'm?xwl=myapp/module-test/sub', // url是引入组件的路径
success(scope) {
//scope 对像是顶层的module实例,包含所有的子元素实例
ct.add(scope.main);
}
});
runModulePanelCt
scope页面结构
log scope
2.怎么给弹窗传递回调函数
main 按钮的点击事件
Wb.run({
url: 'm?xwl=myapp/module-test/common',
owner: 'window1', //destroy the module when window1 is destroyed
success(scope) {
scope.add(3, 5, (total, win) => {
Wb.tip('Total value is: ' + total);
win.close();
});
}
});
弹窗的initialize事件,初始化时给组件实例注册了一个add方法
Wb.apply(app, {
/** @property {Function} callback The callback function. @priv */
/**
* Perform add.
* @param {Number} value1 value 1.
* @param {Number} value2 value 2.
* @param {Function} callback The callback function after completion.
* @param {Number} .total The total value.
* @param {Wb.Window} .win The edit window.
*/
add(value1, value2, callback) {
app.number1.value = value1;
app.number2.value = value2;
app.callback = callback;
app.window1.show();
}
});
弹窗的ok事件,调用callback方法传入实参
app.callback(app.number1.value + app.number2.value, this);
效果 点击确定时会弹出数字的总和。
3.加载js
注意:创建js需要在应用/web创建,模块里面只能创建xwl后缀的文件。
示例:
Wb.load(
'wb/comCheck/js/sysConfig.js',
f => {
setConfigBtnVisible('IMPORT_CLASS_EVALUATION',app.importBtn)
}
);
//loadx是load的promise版本,奇怪可以避免一些空指针的问题
Wb.loadx('wb/comCheck/js/sysConfig.js').then(f=>{
setConfigBtnVisible('IMPORT_CLASS_EVALUATION',app.importBtn)
});
如果只是单纯的引入js,css则可以直接在module中配置links熟悉,如
注意:引入的links必须写在第一行,否则会引入不成功
路径的表示方式
1. xpath 代表当前路径,具体到文件类型
2.使用的绝对路径,目录用/
Wb.open('m?xwl=myapp/test');
3.相对路径,相对的是项目根目录
url:'./sub'
权限配置
- 1.给对应的按钮配置bindModule属性,对应一个xwl的标识位,里面可以不用写逻辑
配置完后对应菜单会增加一个编辑树的选项
- 2.通过用户角色给对应权限赋值
其他一些用到的
- 1.fireEvent可以调用别的组件的事件
app.addDeptBtn.fireEvent('click')
-
2.在多个弹窗组件外面包一层array组件会导致tree控件 contextMenu的点击事件与toolbar的点击事件打开的弹窗元素不一致
-
3.接口调用地址,参数后面拼接的是&xaction
m?xwl=comCheck/checkManagement/service/checkDraftService&xaction=queryDraft
根据实际应用场景进行调整
- 4.设置组件的禁用
app.editDeptBtn.setDisabled(true);
-
5.下拉框的数据来源于后端接口,如果直接配置url为serveScript的地址,则每次点击下拉箭头都会发送请求;写在ready中请求接口地址,或者可以配置loadOnce属性为true,则会在页面初始化时进行请求一次
-
6.select 树形控件如果设置了autoLoad为true,则调用了app.PARENT.refresh(),下拉列表也不刷新
-
7.Wb.raise() 可以用于后端抛出异常,则接口不会是success
-
8.gridColumn可以设置表单占据几行
-
9.样式问题,设置style向下面这样设置
border:1px solid #a0cfff -
10.toggle开关后端返回的“0” 和 “1”会被框架自动隐式转换;实际保存的值是布尔类型,需要处理
-
10 textarea组件不像element一样,有输入字数提示和超限阻止输入的功能,改进建议
- 1.1增加suffix给字数提示
- 1.2change事件中更新输入字数并判断字数超限了阻止用户输入 代码如下:
this.suffix = [this.value.length,this.maxLength].join('/')
if(this.value.length>this.maxLength){
event.preventDefault()
console.log('this.value---before',this.value)
this.value = this.value.substring(0, this.maxLength);
console.log('this.value--after', this.value)
}
但是有个问题,输入字数大于maxLength时有时候也会显示出来,再输入一次后又恢复正常,异步更新原因? 建议只增加一个计数的,不阻止用户输入,因为超限时最终表单也无法提交
11.grid column 设置width:-1会自适应,但是不建议轻易使用,因为列过多且文字过长时会导致文案被遮挡且没有滚动条;可以用在列少的情况下,让其单元格自适应。
12.一些操作元素和样式的api
- addFooter
- addEl
- setStyle
13.普通提示建议使用 Wb.tip(),会自动关闭;Wb.info()还要点击按钮才会关闭
14.点击按钮时如果请求接口数据并给弹窗中的grid赋值,表格的分页会不展示;但是如果给grid配置url,autoLoad为false(避免还没有打开弹窗就请求了列表),在点击时调用grid的load方法并传入参数就可以了
//bad
//good
15.treeItem调用doSelect方法,可以设置某个符合条件的节点进行选中,并且会自动触发selectionChange事件
16.tree组件如果设置了autoSelect会true,会默认选中树的第一个节点;当设置autoSelect为false时,初始化打开ID为undefined,动态设置节点选中后会有值,如果通过ID进行判断会命中一些为空的提示
17.gird控件设置单元格的minWidth,实际还是会出现大屏上表格有留白的情况
因为table没有设置width为100%,而是width为1px。导致table的宽度由各单元格的width总和构成(注意不是minWdith)
而如果设置其中一个单元格的minWdith和width:-1,则应该不会有问题,会增加一个类,设置table的宽度为100%,占满剩余的整个屏幕大小,如下:
注意:需要设置minWidth,避免在小屏上没有剩余空间,该列不显示的问题
18.column中render的代码即使注释了也会影响子组件的渲染
19.setListeners可用于给组件设置监听事件
20.multiSelect设置具体的值,譬如85% 可以调整select输入框的样式;tagWrap 当允许{#multiSelect}多选时,选择的标签按钮是否允许换行
遇到的坑,请慎用
- 1.可编辑表格 Editable grid,使用前端渲染表格的方式,实际在点第一次保存时并未真正触发保存事件,示例中给的是方式是可以的,但未实践是怎么做的
- 2.接1,改成在column的render方法动态创建表单元素的方式,但是textArea控件敲回车时无法换行,代码示例如下
- 3.还是可编辑表格,可编辑单元格是一个Select组件,在ready中给组件的data动态赋值,发现每次新打开弹窗时,数据都是第一次的数据。
场景如下:在列表页面的表格操作栏中点击一个按钮,此时会获取该列表中的一个字段的数据为LIST,打开一个弹窗,弹窗里面有一个可编辑表格组件,其中一个单元格的editor配置的是一个Select组件,在ready中给该组件的data赋值,成功。但是关闭弹窗(弹窗已设置resetDialog属性为true),重新点击列表的另一行数据,此时LIST变更了,但是弹窗中的Select组件的ready函数没有重走,导致下拉数据没有更新。