ExtJS模型中位掩码与布尔值的可复用转换实现方案咨询
解决ExtJS中位掩码与多复选框的双向绑定问题
这问题我之前在项目里也碰到过——ExtJS的表单复选框默认只支持绑定布尔字段,而我们需要和整数位掩码做双向转换,核心思路是用虚拟字段映射位掩码的每一位,再封装可复用的逻辑来同步虚拟字段和实际位掩码字段。下面给你两种方案,从基础实现到优雅复用都有:
基础实现:模型虚拟字段+手动同步
先定义好权限位的映射(必须和后端保持一致!):
// 权限位与整数的映射:read=1(2^0), write=2(2^1), execute=4(2^2) const PERMISSION_BITS = { read: 1 << 0, write: 1 << 1, execute: 1 << 2 };
然后在模型里添加虚拟布尔字段(设置persist: false避免提交到服务器),并通过convert函数从位掩码生成布尔值;同时监听虚拟字段的变化,反向计算更新位掩码:
Ext.define('MyApp.model.Permissions', { extend: 'Ext.data.Model', fields: [ // 实际提交给后端的位掩码字段 { name: 'user', type: 'int' }, { name: 'group', type: 'int' }, { name: 'other', type: 'int' }, // User权限的虚拟布尔字段 { name: 'userRead', type: 'boolean', persist: false, convert: (val, record) => (record.get('user') & PERMISSION_BITS.read) !== 0 }, { name: 'userWrite', type: 'boolean', persist: false, convert: (val, record) => (record.get('user') & PERMISSION_BITS.write) !== 0 }, { name: 'userExecute', type: 'boolean', persist: false, convert: (val, record) => (record.get('user') & PERMISSION_BITS.execute) !== 0 }, // Group和Other的虚拟字段同理,复制上面的结构改前缀即可 { name: 'groupRead', type: 'boolean', persist: false, convert: (val, record) => (record.get('group') & PERMISSION_BITS.read) !== 0 }, { name: 'groupWrite', type: 'boolean', persist: false, convert: (val, record) => (record.get('group') & PERMISSION_BITS.write) !== 0 }, { name: 'groupExecute', type: 'boolean', persist: false, convert: (val, record) => (record.get('group') & PERMISSION_BITS.execute) !== 0 }, { name: 'otherRead', type: 'boolean', persist: false, convert: (val, record) => (record.get('other') & PERMISSION_BITS.read) !== 0 }, { name: 'otherWrite', type: 'boolean', persist: false, convert: (val, record) => (record.get('other') & PERMISSION_BITS.write) !== 0 }, { name: 'otherExecute', type: 'boolean', persist: false, convert: (val, record) => (record.get('other') & PERMISSION_BITS.execute) !== 0 } ], constructor() { this.callParent(arguments); // 监听所有虚拟字段变化,同步更新位掩码 this.mon(this, [ 'change:userRead', 'change:userWrite', 'change:userExecute', 'change:groupRead', 'change:groupWrite', 'change:groupExecute', 'change:otherRead', 'change:otherWrite', 'change:otherExecute' ], this.updatePermissions, this); }, updatePermissions() { // 更新user位掩码 let userPerm = 0; if (this.get('userRead')) userPerm |= PERMISSION_BITS.read; if (this.get('userWrite')) userPerm |= PERMISSION_BITS.write; if (this.get('userExecute')) userPerm |= PERMISSION_BITS.execute; this.set('user', userPerm); // 更新group位掩码 let groupPerm = 0; if (this.get('groupRead')) groupPerm |= PERMISSION_BITS.read; if (this.get('groupWrite')) groupPerm |= PERMISSION_BITS.write; if (this.get('groupExecute')) groupPerm |= PERMISSION_BITS.execute; this.set('group', groupPerm); // 更新other位掩码 let otherPerm = 0; if (this.get('otherRead')) otherPerm |= PERMISSION_BITS.read; if (this.get('otherWrite')) otherPerm |= PERMISSION_BITS.write; if (this.get('otherExecute')) otherPerm |= PERMISSION_BITS.execute; this.set('other', otherPerm); } });
最后表单里的复选框直接绑定这些虚拟字段就行:
Ext.create('Ext.form.Panel', { bind: '{myPermissionRecord}', items: [ { xtype: 'checkboxfield', boxLabel: 'read', bind: '{userRead}' }, { xtype: 'checkboxfield', boxLabel: 'write', bind: '{userWrite}' }, { xtype: 'checkboxfield', boxLabel: 'execute', bind: '{userExecute}' }, // Group和Other的复选框同理绑定对应的虚拟字段 ] });
优雅复用:封装成Mixin
上面的基础实现虽然能用,但重复代码太多。我们可以把位掩码转换逻辑封装成Mixin,让任何需要的模型都能快速集成:
Ext.define('MyApp.mixin.PermissionBitmask', { config: { // 配置需要转换的位掩码字段,键是模型字段名,值是虚拟字段的前缀 permissionFields: { user: 'user', group: 'group', other: 'other' }, // 权限位映射,和后端保持一致 permissionBits: { read: 1 << 0, write: 1 << 1, execute: 1 << 2 } }, initPermissionBitmask() { const me = this; const permFields = me.getPermissionFields(); const permBits = me.getPermissionBits(); // 动态给模型添加虚拟字段 Ext.Object.each(permFields, (fieldName, prefix) => { Ext.Object.each(permBits, (permName, bitVal) => { const virtualFieldName = `${prefix}${Ext.String.capitalize(permName)}`; me.addField({ name: virtualFieldName, type: 'boolean', persist: false, convert: (val, record) => (record.get(fieldName) & bitVal) !== 0 }); }); // 监听当前位掩码字段对应的所有虚拟字段变化 const changeEvents = Object.keys(permBits).map(permName => `change:${prefix}${Ext.String.capitalize(permName)}` ); me.mon(me, changeEvents.join(' '), () => { let newPerm = 0; Ext.Object.each(permBits, (permName, bitVal) => { const virtualFieldName = `${prefix}${Ext.String.capitalize(permName)}`; if (me.get(virtualFieldName)) newPerm |= bitVal; }); me.set(fieldName, newPerm); }, me); }); }, constructor() { this.callParent(arguments); this.initPermissionBitmask(); } });
然后你的模型只需要引入这个Mixin即可,无需重复写转换逻辑:
Ext.define('MyApp.model.Permissions', { extend: 'Ext.data.Model', mixins: ['MyApp.mixin.PermissionBitmask'], fields: [ { name: 'user', type: 'int' }, { name: 'group', type: 'int' }, { name: 'other', type: 'int' } ], // 如果你需要新增其他位掩码字段,直接修改config就行 // config: { // permissionFields: { // user: 'user', // group: 'group', // other: 'other', // admin: 'admin' // 新增的位掩码字段 // } // } });
关键注意事项
- 确保
permissionBits的映射和后端完全一致,否则转换会出错; - 虚拟字段必须设置
persist: false,避免store.sync时把这些布尔字段提交到服务器; - 如果后端的位顺序有变化(比如execute是第0位),只需要修改
permissionBits里的位值即可。
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

