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中请求接口地址,则会在页面初始化时进行请求一次
相关推荐
0wioiw04 分钟前
Flutter基础(前端教程④-组件拼接)
前端·flutter
花生侠28 分钟前
记录:前端项目使用pnpm+husky(v9)+commitlint,提交代码格式化校验
前端
一涯36 分钟前
Cursor操作面板改为垂直
前端
我要让全世界知道我很低调43 分钟前
记一次 Vite 下的白屏优化
前端·css
1undefined244 分钟前
element中的Table改造成虚拟列表,并封装成hooks
前端·javascript·vue.js
蓝倾1 小时前
淘宝批量获取商品SKU实战案例
前端·后端·api
comelong1 小时前
Docker容器启动postgres端口映射失败问题
前端
花海如潮淹1 小时前
硬件产品研发管理工具实战指南
前端·python
用户3802258598241 小时前
vue3源码解析:依赖收集
前端·vue.js