【发布时间】:2019-10-23 03:43:30
【问题描述】:
问题摘要
- 使Vuex store模块A的突变或动作调用外部函数。它可能是其他 Vuex 存储模块(例如 B)的突变或操作。
- A 必须保存到外部方法的链接(例如,其他 Vuex 存储模块 B 的突变或操作),因为它将被间接调用,而不是立即调用。
在下面的例子中:
-
A 将是
RollbackActionFloatingPanelStoreModule -
B 将是
OtherStoreModule - 外部函数为
rollbackRemoveItem
示例(何时可以使用)
这个浮动撤消面板显然允许撤消用户的操作,但是必须实现撤消方法。另外,由于undo面板必须回滚多种用户的控制动作,所以每次都需要指定undo方法的实现。
$ref 不适合基于 TypeScript 的 Vue,所以让$ref 解决方案将是最后的希望。这是我想将撤消面板状态和行为完全委托给 Vuex 模块,因此 Vue 组件将是无逻辑的:
import { Vue, Component } from "vue-property-decorator";
import { getModule } from "vuex-module-decorators";
import template from "./RollbackActionFloatingPanel.pug";
import RollbackActionFloatingPanelStoreModule
from "@Store/modules/AssociatedWithComponents/RollbackActionFloatingPanel";
@Component({ template })
export default class RollbackActionFloatingPanel extends Vue {
private readonly relatedStoreModule: RollbackActionFloatingPanelStoreModule =
getModule(RollbackActionFloatingPanelStoreModule);
}
组件模板(pug 语言;svg 图标被封装到 pug mixins)
transition(name="rollback_action_floating_panel")
.RollbackActionFloatingPanel(v-show="relatedStoreModule.displayFlag")
+Checkmark__Simple__Bold--MaterialDesignIcon.RollbackActionFloatingPanel-CheckmarkIcon
.RollbackActionFloatingPanel-Text {{ relatedStoreModule.message }}
button.RollbackActionFloatingPanel-Button(@click="relatedStoreModule.onClickRollbackButton")
+Undo__Simple--MaterialDesignIcon.ButtonWithPrependedIcon-Icon
| Undo
button.RollbackActionFloatingPanel-Button.RollbackActionFloatingPanel-Button__Primary(@click="relatedStoreModule.dismiss")
+Hide__StrikethroughEye__Filled--MaterialDesignIcon.ButtonWithPrependedIcon-Icon
| Hide
vuex store RollbackActionFloatingPanel 只需要一个公共方法:displayAndHideALittleLater。它可以从其他 store 模块或 Vue 组件中调用。从逻辑上讲,我们可以将 undo 方法实现指定为参数 (displayAndHideALittleLater(payload: { message: string; onClickRollbackButton: Function; }))。
方法 onClickRollbackButton 和 dismiss 是从模板调用的,所以 TypeScript 在这种情况下不能禁止它的调用,即使它们不是公开的。
import { VuexModule, Module, Mutation, Action } from "vuex-module-decorators";
import store, { StoreModuleNames } from "@Store/Store";
@Module({
name: "VUEX_MODULE:UNDO_PANEL",
store,
dynamic: true,
namespaced: true
})
export default class RollbackActionFloatingPanelStoreModule extends VuexModule {
private static readonly AUTO_HIDE_TIMEOUT__MILLISECONDS: number = 5000;
private _displayFlag: boolean = false;
private _message: string = "";
private _onClickRollbackButton: Function = () => {};
@Action
public displayAndHideALittleLater(
{
message,
onClickRollbackButton
}: {
message: string;
onClickRollbackButton: Function;
}
): void {
this.setMessage(message);
this.setOnClickRollbackButtonEventHandler(onClickRollbackButton);
this.display();
setTimeout(
(): void => { this.dismiss(); },
RollbackActionFloatingPanelStoreModule.AUTO_HIDE_TIMEOUT__MILLISECONDS
);
}
@Action
private onClickRollbackButton(): void {
this._onClickRollbackButton();
}
@Mutation
private setMessage(message: string): void {
this._message = message;
}
@Mutation
private setOnClickRollbackButtonEventHandler(newHandler: Function): void {
this._onClickRollbackButton = newHandler;
}
@Mutation
private display(): void {
this._displayFlag = true;
}
@Mutation
private dismiss(): void {
this._displayFlag = false;
this._onClickRollbackButton = () => {};
}
public get displayFlag(): boolean { return this._displayFlag; }
public get message(): string { return this._message; }
}
其他 Vuex 模块的用法:
import { VuexModule, Module, Mutation, getModule } from "vuex-module-decorators";
import store, { StoreModuleNames } from "@ProjectInitializer:Store/Store";
import RollbackActionFloatingPanelStoreModule
from "@ProjectInitializer:Store/modules/AssociatedWithComponents/RollbackActionFloatingPanel";
@Module({
name: "VUEX_MODULE:OTHER"
store,
dynamic: true,
namespaced: true
})
export default class OtherStoreModule extends VuexModule {
private _selectedItems: Array<Item> = getDefaultItemsFromRepsitory();
private _lastDeletedItem: Item | null = null;
@Mutation
public removeItem(targetItemId: string): void {
const targetItemSearchingPredicate: (item: Item) => boolean =
(item: Item): boolean => item.id === targetItemId;
const targetItem: Item | undefined = this._selectedItems.find(targetItemSearchingPredicate);
if (typeof targetItem === "undefined") { return; }
this._lastDeletedItem = targetEntryPointsGroupSettings;
const indexOfTargetItem: number = this._selectedItems.findIndex(targetItemSearchingPredicate);
if (indexOfTargetItem !== -1) {
this._selectedItems.splice(indexOfTargetItem, 1);
} else {
return;
}
getModule(RollbackActionFloatingPanelStoreModule).displayAndHideALittleLater({
message: "Item deleted",
onClickRollbackButton: (): void => { this.rollbackRemoveItem(); }
});
}
@Mutation
public rollbackRemoveItem(): void {
if (this._lastDeletedItem === null) { return; }
this._selectedItems.unshift(this._lastDeletedItem);
this._lastDeletedItem = null;
}
}
错误
Error: ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access this.someMutation()
or this.someGetter inside an @Action?
That works only in dynamic modules.
If not dynamic use this.context.commit("mutationName", payload) and
this.context.getters["getterName"]
Error: Could not perform action onClickRollbackButton
发生。因为我所有的模块都是动态的,所以错误信息可能不准确。事实上,我们通过非修饰函数_onClickRollbackButton通过动作onClickRollbackButton调用突变rollbackRemoveItem。我不能这么轻易地避免_onClickRollbackButton,因为我需要将撤消方法的实现存储在某个地方,直到dismiss 突变将被执行。
尝试使用静态类字段
@Module({
name: "VUEX_MODULE:UNDO_PANEL",
store,
dynamic: true,
namespaced: true
})
export default class RollbackActionFloatingPanelStoreModule extends VuexModule {
private static readonly AUTO_HIDE_TIMEOUT__MILLISECONDS: number = 5000;
private _displayFlag: boolean = false;
private _message: string = "";
private static _onClickRollbackButton: Function = () => {};
// ...
@Action
private onClickRollbackButton(): void {
RollbackActionFloatingPanelStoreModule._onClickRollbackButton();
}
@Mutation
private setOnClickRollbackButtonEventHandler(newHandler: Function): void {
RollbackActionFloatingPanelStoreModule._onClickRollbackButton = newHandler;
}
}
同样的错误。
复制
我会以GitHub Repository 的身份分享repro,直到这个问题得到解决。如果您愿意克隆或下载此存储库,请在项目目录中执行npm i && npm run JavaScriptBuild。一旦安装了所有 npm 依赖项,webpack 将构建项目,您可以在 http://localhost:8081/ 上打开结果
【问题讨论】:
标签: typescript vue.js vuex vuex-modules