WebBuilder

组件

不同于我们常用的Element组件库,示例和代码都在一起,方便直接进行示例代码的复制粘贴。

v8pro的组件示例见示例,示例代码见模块-example示例,我们可以在示例代码中点击运行查看对应的组件效果。

1.布局组件

  • viewport 类比为 div ,可以通过设置layout属性调整其内部元素的布局(是一个全屏的盒子,页面上所有的元素必须为他的子级,否则展示不出来;但弹窗可以使用array组件与viewport平级 下 放 window组件)
  • pannel layout设置为row 内部表单元素会按照inline方式进行布局

  • container 容器组件,比如页面需要加载另一个组件,需要一个container容器

  • card

以上几个没看出有啥区别

2.表单组件

  • 没有专门的form组件,通常使用pannel进行包裹各表单项,进行表单项的布局,比如水平,垂直或inline

  • 表单校验,示例:

js 复制代码
if (Wb.verify(app.viewport1)) {
  Wb.ajax({
    url: xpath + '&xaction=save',
    comps: app.viewport1,
    success() {
      Wb.tipDone();
    }
  });
}
  • required ,tip ,validator 等都可以在属性中定义

  • ajax提交数据时,可以直接通过下面方式获取表单数据

js 复制代码
Wb.getValue(app.viewport1) //会收集所有含有value的键值对,比如{userName:'admin'}
app.Cid.getValue()  //获取某个组件实例的value值。 注意:cid必须是唯一的,比如页面的查询项和弹窗中的表单项不能取相同的cid,否则无法获取到值
Wb.apply({},Wb.getValue(app.viewport1)) // apply对象的合并
  • 表单重置
js 复制代码
Wb.reset(app.panel1)

3.表格组件grid

  • 1.表格如果需要mock数据,可以在grid组件中配置localData的值

  • 2.服务端渲染的表格 可以 url 链接到对应的代码

  • 3.增删改查后更新表格数据
js 复制代码
app.grid1.reload() //会自动调用后端查询接口
  • 4.带操作的表格列如果想要生效一定要把array组件的cid改成buttons;一定要把array组件的cid改成columns,否则内容不展示
  • 5.grid的toolbar组件如果要展示,必须设置isProperty属性为true,否则会当成表格内容进行渲染,加了后才会向下面这样渲染
  • 6.column必须设置的属性 fieldName 相当于element的prop,对应后端返回的字段名称
  • 7.text可以设置列标题,width可以设置列宽度,renderer属性可以通过js自定义单元格HTML的输出

render示例一:根据不同状态设置单元格为不同的tag

js 复制代码
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

js 复制代码
let pTag = el.addEl('my-link','div')
pTag.innerHTML = this.data.privateStatute // this.data可以获取该行的数据
  • 8.设置editable属性为true可以设置表格为可编辑,可编辑表格必须作为对应的column设置editor属性,如果未设置editor属性那么该列仍然不可编辑。

  • 9.表格添加行

js 复制代码
app.editableGrid.addRecord();
  • 10.实操中常用的属性
    • data 获取显示的数据,和element-ui一致。

注意:如果要实现页面的响应式更新,需要替换一个数组,单纯的调用数组的变异方法是不生效的,这点有别与vue的列表渲染

示例:

js 复制代码
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有啥区别
js 复制代码
  app.grid1.selections
  app.grid1.selectionData
  app.grid1.originData  
  Wb.getActionHint(recs, 'id') //获取选中数据的唯一标识,调用getActionHint方法进行二次确认
  delRecords 删除行,直接删掉了,无需刷新列表

4.弹窗组件

  • 1.使用的是window组件,设置弹窗的标题是title属性,记住不能设置text,text代表的是body里面的内容,如果设置了text,则下面的子元素会不显示。

  • 2.打开关闭弹窗

```js

app.autoResetWin.show();

app.autoResetWin.close();

```

  • 3.如果在关闭之前需要执行一定操作,需要配置closeAction为destory,同时添加destory事件

  • 4.新增和编辑时打开弹窗,示例

js 复制代码
 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进行赋值的。

js 复制代码
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,给空字符串是可以的,示例如下:
    js 复制代码
      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 = "新增底稿"

5.tree和select

  • 1.数据来源于接口,只需要配置url属性即可
  • 2.可以在success事件中对请求回来的数据做处理,比如
js 复制代码
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中阻止对应节点的选中

js 复制代码
if (!item.leaf) {
  Wb.tip('Please select a leaf node');
  return false;
}
  • 3.需要手动加上leaf属性,才会展示会文件形式,否则都是文件夹目录

  • 4.subTextField可以设置副文本,值为后端对应的字段名称

5.treeSelect只有设置了treePicker {itemsPath:'children'}子级才会正确展示,itemsPath为子级展示的后端字段名称

数据请求

  • Wb.ajax

  • Wb.request

  • Wb.Request.ajax

常用的serveScript

建表语句

js 复制代码
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中写下面代码

js 复制代码
//后端
方式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.删

js 复制代码
//方式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.load() //会发送请求
      }
    });
  });
}
handleDel()

3.改

js 复制代码
//后端
//方式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,否则初始化查询没有数据

js 复制代码
//后端:
//方式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
  }
})

注意事项总结: 1.项目中的目录结构为,xpath代表同名目录,所以请求地址可以写成url:xpath+'/update'

2.项目中新增和修改用的是2个弹窗,因为ok事件调用的接口不一样。暂时还不知道怎么在点击事件时给弹窗传递标识(区分是新增还是编辑),后期可以再看看

组件化与模块化

common.js

AMD

CMD

esmodule

1.页面中如何引入一个组件,示例,下面是一个按钮的点击事件

js 复制代码
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 按钮的点击事件

js 复制代码
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方法

js 复制代码
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方法传入实参

js 复制代码
app.callback(app.number1.value + app.number2.value, this);

效果 点击确定时会弹出数字的总和。

3.加载js 。TODO:无法创建js后缀的文件

路径的表示方式

1. xpath 代表当前路径,具体到文件类型

2.使用的绝对路径,目录用/

Wb.open('m?xwl=myapp/test');

3.相对路径,相对的是项目根目录

url:'./sub'

其他一些用到的

  • 1.fireEvent可以调用别的组件的事件
js 复制代码
app.addDeptBtn.fireEvent('click')
  • 2.在多个弹窗组件外面包一层array组件会导致tree控件 contextMenu的点击事件与toolbar的点击事件打开的弹窗元素不一致

  • 3.接口调用地址,参数后面拼接的是&xaction

m?xwl=comCheck/checkManagement/service/checkDraftService&xaction=queryDraft

根据实际应用场景进行调整

  • 4.设置组件的禁用
js 复制代码
app.editDeptBtn.setDisabled(true);
  • 5.下拉框的数据来源于后端接口,如果直接配置url为serveScript的地址,则每次点击下拉箭头都会发送请求;写在ready中请求接口地址,则会在页面初始化时进行请求一次
相关推荐
学不会•2 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
活宝小娜4 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点4 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow4 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o4 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā5 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年7 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder7 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_882727577 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架