使用Vue时,一直都有一个令人头疼的问题。v-model
了一个computed
参数无法调用其set函数进行修改。 从而导致Vuex使用起来非常麻烦,需要一个参数一个参数进行computed
。而这个问题在Vue3上可以得到解决。
话不多说,先贴上代码:
/**
* 深computed实现
* 将传入的整个Obj转换成computedObj
* 并使用reactive去除ref
*
* @param get getter
* @param set setter
* @param ignoreKey 忽略转换的Key
* @returns computedObj
*/
export function deepComputed<T extends object, K extends keyof T>(
get: () => T,
set?: (newObj: T, key: string, newVal: any) => void,
...ignoreKeys: K[]
): Option<T> {
const obj = get(),
keys = Object.keys(obj),
tempObj: Option<T> = Object.create(null)
const isWrite = typeof set === "function"
for (let key of keys) {
if (ignoreKeys.includes(key as K)) {
continue
} else if (isWrite) {
tempObj[key] = computed({
get: () => get()[key],
set: newVal => {
const newObj = Object.assign({}, get(), { [key]: newVal })
set(newObj, key, newVal)
}
})
} else {
tempObj[key] = computed(() => get()[key])
}
}
return reactive(tempObj)
}
实现其实非常简单,就是遍历对象按需求转换成computed
并重新赋值到新对象。 这个可以实现转换成computedObj
,但是这样实现的方式只适用于只读 (赋值后会覆盖掉该参数的computed
实现),只读也没必要把整个对象成员转换成computedObj
。
而在 Vue3 上有响应式的实现reactive
, 我们只需要把computedObj
转换成响应式对象。
return reactive(tempObj)
在这样处理这之后,Vue会代理该对象。在对象进行赋值时参数会传递到Vue响应式实现的代理,代理会进行判断处理对象内的computed get set
。
从而解决了之前赋值问题。
例子
<setting-item lable="导航栏" horizontal>
<a-switch v-model:checked="topSiteSetting.enable" />
</setting-item>
const topSiteSetting = deepComputed(
() => store.state.setting.topSite,
updateTopSiteSetting,
...otherKeys(store.state.setting.topSite, "col", "row", "gap", "enable")
)
function updateTopSiteSetting(data: Option<TopSiteSetting>) {
store.commit(SettingMutations.updateTopSiteSetting, data)
}
使用就如同原生computed, set回调更新后的newObj
key
value
。
文章评论