需求
初始需求是 有一个对象,他的某几个属性变更时,触发视图层变动的方法。
当前对象
_battleState: IBattleState = {
isGameOver: false,
bossComing: false,
overType: OverType.None,
isRevive: false,
direction: Direction.S,
isClearDirectionUnits: false
}
get battleState() {
return this._battleState
}
set battleState(val) {
console.log('this._battleState.direction', this._battleState.direction)
console.log('set battleState', val)
console.log('val.direction', val.direction)
if (val.direction !== this._battleState.direction) {
console.log('整体 val.direction !== this._battleState.direction', val.direction)
BattleModelSystem.vmBattleStateJindu(val.direction)
}
this._battleState = val
}
事件触发
console.log('在设置前_BattleModelComp.battleState.direction', _BattleModelComp.battleState.direction)
// 老的错误方法
_BattleModelComp.battleState = Object.assign( _BattleModelComp.battleState, { direction: Direction.W })
// 新的正确方法是在Object.assign前新增一个空对象{}
产生的问题
实际的打印情况是
在设置前_BattleModelComp.battleState.direction S
this._battleState.direction W
BattleModelComp.ts:87 set battleState {isGameOver: false, bossComing: false, overType: 'none', isRevive: false, direction: 'W', …}
BattleModelComp.ts:88 val.direction W
在set battleState(val)中的第一行中
this._battleState.direction W
这个值就已经被改为了W
问题所在
是因为对象引用,在
_BattleModelComp.battleState = Object.assign( _BattleModelComp.battleState, { direction: Direction.W })
中Object.assign时,引用对象就已经被改为新的值了
解决问题
在Object.assign中的第一位新增一个空对象,使目标对象是一个新的对象
Object.assign( {},_BattleModelComp.battleState, { direction: Direction.W })
其他方法:使用Proxy
在上面的方法的缺陷
在上面的方法中
get battleState
set battleState
只有在整体被赋值时才会改变
比如:
_BattleModelComp.battleState = Object.assign({}, _BattleModelComp.battleState, { direction: Direction.W })
如果只改变一个属性则不会被触发,如下面的
_BattleModelComp.battleState.direction = Direction.W
这个时候就尝试Proxy的改进
_battleState: IBattleState = {
isGameOver: false,
bossComing: false,
overType: OverType.None,
isRevive: false,
direction: Direction.S,
isClearDirectionUnits: false
}
get battleState() {
return this.proxy_battleState
}
set battleState(val) {
for (const key in this._battleState) {
this.proxy_battleState[key] = val[key]
}
}
proxy_battleState: IBattleState = {
isGameOver: false,
bossComing: false,
overType: OverType.None,
isRevive: false,
direction: Direction.S,
isClearDirectionUnits: false
}
constructor() {
super();
this.proxy_battleState = new Proxy(this._battleState, handler);
}
const handler = {
set(obj, prop, value) {
if (prop == 'direction' && obj[prop] != value) {
console.log('direction is change', value, obj[prop])
}
obj[prop] = value;
return true
}
}
这样无论整体被修改还是局部属性被修改都会监听到
_BattleModelComp.battleState = Object.assign({}, _BattleModelComp.battleState, { direction: Direction.C }) // 会走set battleState 中的方法,接着全部属性进行proxy
_BattleModelComp.battleState.direction = Direction.W // 单个属性进行proxy