【问题标题】:Dynamic function for Vuex store module on floating undo bar example浮动撤消栏示例上 Vuex 商店模块的动态功能
【发布时间】:2019-10-23 03:43:30
【问题描述】:

问题摘要

  1. 使Vuex store模块A的突变或动作调用外部函数。它可能是其他 Vuex 存储模块(例如 B)的突变或操作。
  2. 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; }))。

方法 onClickRollbackButtondismiss 是从模板调用的,所以 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 &amp;&amp; npm run JavaScriptBuild。一旦安装了所有 npm 依赖项,webpack 将构建项目,您可以在 http://localhost:8081/ 上打开结果

【问题讨论】:

    标签: typescript vue.js vuex vuex-modules


    【解决方案1】:

    你实现了 store rollbackRemoveItem 吗?

    你也许可以使用类似这样的东西:

    connect() {
      const connection = getModule(Connection, this.$store);
      connection.testAction();
      this.$store.dispatch('Connection/rollbackRemoveItem');
    }
    

    【讨论】:

    • 感谢您的回答。当然,我已经实现了这个方法。尝试您的解决方案时,我会再次发表评论。
    猜你喜欢
    • 2021-04-10
    • 2017-11-09
    • 2018-05-19
    • 1970-01-01
    • 2014-01-29
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多