状态机Vuex的奇淫巧技-多弹框、多事件统一控制

2,189 阅读1分钟

​ 现实中的许多Web应用都有许多弹框,或者交互事件的开发需求。博主曾开发过较大型的Vue Web应用,光控制这些弹框的显示隐藏都感觉恶心:初始化isDialogShow=false,点击按钮isDialogShow=true,弹框显示后点击确认、取消和关闭按钮需要广播事件或者通过$parent将父组件的isDialogShow置为false。还有就是跨组件的事件广播也让人头大。如若弹框比较多或者跨组件事件较多,采用生硬的控制显得很不优雅。

​ 福音来了,如若你的Vue应用已经自带vuex或者应用交互过多需要引入vuex,那么下面的方案将是个不错的解决方案。先说一下用vuex统一管理弹框和事件优点:统一控制,一目了然控制简单。其相关概念可查看vuex,这里就不赘述了。

  1. 初始化state

    state: {
      // 弹框信息显示控制标识统一定义于此,统一管理
      BooleanFlag: {
        //小驼峰:is 名词 动词
        isDemoDialogShow: false, // demo 弹框显示
      },
      // 事件直通车, 相关事件可以统一管理
      EventBus: {
        Page1ToPage2: {}, // 采用对象是为了传递数据
      }
    }
    
  2. 定义mutations

    mutations: {
      // 自动取反
      BooleanFlag(state, flagKeys) {
        if (!Array.isArray(flagKeys)) return
        const BooleanFlag = state.BooleanFlag
        flagKeys.forEach(flagKey => BooleanFlag[flagKey] = !BooleanFlag[flagKey])
      },
      // EventBus
      EventBus(state, eventWithData={}) {
        const EventBus = state.EventBus
        Object.keys(eventWithData).forEach(eventKey=>{
          if(EventBus[eventKey] !== undefined){
            EventBus[eventKey] = eventWithData[eventKey]
          }
        })
      }
    }
    
  3. 父组件应用

    <template>
      <div>
        <div class="button-bar">
          <el-button @click="onDialogShow" type="primary">打开弹框</el-button>
          <el-button @click="onEmitData" type="primary">广播数据</el-button>
        </div>
        <div>
          <demo-dialog v-if="BooleanFlag.isDemoDialogShow"></demo-dialog>
        </div>
      </div>
    </template>
    
    <script>
    import { mapState } from "vuex";
    import DemoDialog from "@/dialogs/DemoDialog";
    export default {
      components: {
        DemoDialog
      },
      computed: mapState(["BooleanFlag"]),
      methods: {
        // 弹框Demo
        onDialogShow() {
          this.$store.commit("BooleanFlag", ["isDemoDialogShow"]);
        },
        // 广播事件
        onEmitData() {
          const messageObj = {
            message: "from page1"
          };
          this.$store.commit("EventBus", {
            Page1ToPage2: messageObj
          });
        }
      }
    };
    
  4. 弹框组件的应用

    <template>
      <div>
        <el-dialog :title="title" :visible.sync="isShow" :width="width" custom-class="ht-dialog" :before-close="onCancle">
          <div class="dialog-container">
            弹框内容
          </div>
          <div class="bottom-buttons">
            <el-button @click="onCancle">{{$t('Common.cancel')}}</el-button>
            <el-button type="primary" @click="onSure">{{$t('Common.sure')}}</el-button>
          </div>
        </el-dialog>
      </div>
    </template>
    
    <script>
    export default {
      name: "DemoDialog",
      data() {
        return {
          title: "弹框标题",
          width: "500px",
          isShow: true
        };
      },
      methods: {
        onSure() {
          // 业务代码
          this.onCancle()
        },
        onCancle() { // 关闭弹框
          this.$store.commit("BooleanFlag", ["isDemoDialogShow"]);
        }
      }
    };
    </script>
    
  5. 兄弟页面的应用(响应事件)

注意这里要配合 来使用,采用监听数据变化的方式来响应事件。

<template>
  <div>
    page2下的内容
  </div>
</template>
<script>
import { mapState } from "vuex";
export default {
  computed: mapState(["EventBus"]),
  watch: {
    "EventBus.Page1ToPage2": function(message) {
      console.log("Page1ToPage2", message);
    }
  }
};
</script>