此问题来源于最近工作过程中所遇到的,涉及多个状态及每一步操作或者手动刷新后状态更新,在状态更新的过程中不出现明显的停顿(从头判断)。
  由于关系是父子组件,所以不采用路由切换来实现,而是采用父子组件,父组件强制执行子组件方法,子组件执行完毕后$emit一个父组件的方法,这中间结合缓存来控制状态的变更。具体代码如下(只涉及关键部分),由于父组件是主页,所以初始状态保存需在登录页进行处理。

登录页

<!--忽略html部分-->

<script>
  import {getStateByID} from '@/api/xxx'

  export default {
    name: 'login',
    data() {
        return {

        }
    },
    ...
    methods: {
        getNowState(id) {
          id = parseInt(id)
          getStateByID(id)
          .then(res => {
            let state = -1; //-1为最初始状态
            if (res.success) {
              if (res.data && res.data.length > 0) {
                //其他逻辑
                state = res.data[0].state;
              }
            } else {
              console.log(res.message);
            }
             //这里防止多个覆盖
            sessionStorage.setItem(`state${id}`,state)
            this.$router.push({ path: this.redirect || "/" });
            //跳转主页
          })
          .catch(err => {
            //报错逻辑
          });
        }
    }
</script>

父组件

<template>
  <div>
    <div class="test">
      <span class="head">
        <i class="iconfont icon-enterprise" style="margin-right: 5px;"></i>
        测试弹框
      </span>
      <div class="content">
        <div class="right">
          <el-steps :active="activeStep" align-center finish-status="success">
            <el-step
              title="弹出子组件"
              :status="
                disableState === 7
                  ? 'error'
                  : disableState === -1
                  ? 'wait'
                  : disableState === 0
                  ? 'process'
                  : ''
              "
            >
              <div slot="description" class="description">
                <el-button
                  size="small"
                  @click="showSonComponent"
                  :disabled="disableState > 0 && disableState != 7"
                >
                  弹出子组件
                </el-button>
              </div>
            </el-step>
            ...
            <!--省略不必要步骤-->
          </el-steps>
        </div>
    </div>
    <!--子组件弹框-->
    <son-component @getNowStatus="getNowStatus" ref="sonComponent" />
  </div>
</template>

<script>
import SonComponent from "./sonComponent";
import { getID } from "@/utils/xxx";
import { getStateByID } from "@/api/xxx";
export default {
  name: "FatherComponent",
  components: {
    SonComponent
  },
  data() {
    return {
      //步骤
      activeStep: 0,
      //状态文字
      statusStr: "测试步骤0",
      //状态
      disableState: sessionStorage.getItem(`state${getID()}`) || -1,
      color: "failed",
        //状态转换文字
      statusDict: [
        { name: "测试步骤1", color: "finished" },
        { name: "测试步骤2", color: "passed" },
        { name: "测试步骤3", color: "finished" },
        { name: "测试步骤4", color: "passed" },
        { name: "测试步骤5", color: "wait-audit" },
        { name: "测试步骤6", color: "final-passed" },
        { name: "测试步骤7", color: "failed" },
        { name: "测试步骤8", color: "failed" },
        { name: "测试步骤9", color: "failed" },
        { name: "测试步骤10", color: "failed" }
      ],
      stepStatus: [1, 2, 3, 4, 5, 5, 4, 3, 2, 1] //控制步骤条停顿
    };
  },
  computed: {
    id: {
      get() {
        return getID();
      },
      set() {}
    }
  },
  created() {
    //绑定刷新事件
    window.addEventListener("beforeunload", this.getNowStatus(this.id), true);
  },
  mounted() {
    //如果不是初始状态,直接判断
    if (this.disableState != -1) {
      this.changeStatetoStr(this.disableState);
    } else {
    //否则调用接口转换,针对刚开始什么都没有的状态
      this.getNowStatus(this.uid);
    }
  },
  methods: {
    showSonComponent() {
      this.$store.commit("SON_COMPONENTSHOW"); //用简单vuex控制对话框弹出与否
      this.$refs.sonComponent.getNowStatus(this.uid);
    },

    //获取当前状态
    getNowStatus(id) {
      id = parseInt(id);
      getStateByID(id)
        .then(res => {
          if (res.success) {
            if (res.data && res.data.length > 0) {
              const company = res.data[0];
              this.changeStatetoStr(company.state);
            } else {
              this.disableState = -1;
              this.statusStr = "测试步骤0";
              this.activeStep = 0;
              this.color = "failed";
            }
          } else {
            //失败逻辑
          }
        })
        .catch(err => {
          //异常逻辑
        });
    },

    //转换状态文字,调整步骤和状态
    changeStatetoStr(state) {
      state = parseInt(state);
      this.disableState = state;
      this.statusStr = this.statusDict[state].name;
      this.color = this.statusDict[state].color;
      this.activeStep = this.stepStatus[state];
      sessionStorage.setItem(`state${this.uid}`, state); //更新缓存
    }
  },
  //清除刷新监听
  destroyed() {
    window.removeEventListener("beforeunload",
      this.getNowStatus(this.id), true
    );
  }
};
</script>

子组件

<template>
  <div>
    <el-dialog
      title="测试子组件"
      :visible.sync="sonVisible"
      @close="close"
      :close-on-click-modal="false"
      :modal-append-to-body="false"
      v-el-drag-dialog="true"
      append-to-body
      width="50%"
      top="30px"
    >
            <div style="float:right;">
              <el-popover placement="bottom" width="320" trigger="manual" v-model="showUploadList">
                <div v-if="showUploadList" class="upload-list">
                  <p class="head">
                    <span>文件下载</span>
                    <span @click="showUploadList = false">
                      <i class="el-icon-close"></i>
                    </span>
                  </p>
                  <ul v-if="uploadList.length > 0" class="content">
                    <li v-for="(file, index) in uploadList" :key="index">
                      <span class="left" :title="file.name">
                        <a :href="file.url" target="_blank">{{ file.name }}</a>
                      </span>
                      <span class="right">
                        <a :href="file.url" target="_blank">
                          <i class="el-icon-download" style="color:#409eff;"></i>
                        </a>
                        <i class="el-icon-delete" style="color:#ff5757;" @click="deleteFile(index)"></i>
                      </span>
                    </li>
                  </ul>
                  <p
                    v-else
                    style="text-align:center;color:#ccc;line-height:30px;margin:10px 0;"
                  >——&nbsp;暂无附件&nbsp;——</p>
                  <p class="footer-button">
                    <el-upload
                      class="upload-demo"
                      :action="`${host}/uploadAction`"
                      multiple
                      auto-upload
                      :show-file-list="false"
                      :on-success="uploadFile"
                    >
                      <el-button
                        size="small"
                        icon="el-icon-paperclip"
                        style="background-color:#5280b0"
                      >上传附件</el-button>
                    </el-upload>
                  </p>
                </div>
                <el-button
                  size="small"
                  icon="el-icon-paperclip"
                  slot="reference"
                  style="background-color:#409eff !important"
                  @mouseenter.native="showUploadList = true"
                >文件列表</el-button>
              </el-popover>
            </div>
          </div>
      <div slot="footer" style="text-align: center;">
        <el-button size="small" @click="submit" style="width:100px;">提交</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getByPid } from "@/api/xxx";
import { getID } from "@/utils/auth";
import { web_config } from "@/utils/config"; //上传文件用的端口
import { getStateByID } from "@/api/xxx";
export default {
  name: "SonComponent",
  data() {
    return {
      ...
      //上传附件弹窗
      showUploadList: false,
      //上传文件列表
      fileList: [],
      //上传成功后转换的列表
      uploadList: [],
      //域名地址
      host: web_config.host,
      //企业入园id
      pid: 0,
      //状态
      state: 0,
       ...
    };
  },
  mounted() {
    this.getNowStatus(this.id); //获取当前状态
  },
  computed: {
    sonVisible: {
      get() {
        return this.$store.state.SON_COMPONENT;
      },
      set() {}
    },
    //用户id
    id: {
      get() {
        return getID();
      },
      set() {}
    }
  },
  methods: {
    //关闭窗口
    close() {
      this.showUploadList = false; //关闭上传文件框
      this.$store.commit("SON_COMPONENTCLOSE"); //关闭对话框
      //刷新重新获取数据
      this.reset(); //清空数据
      this.$emit("getNowStatus", this.id); //调用父组件刷新状态方法
    },
    //清空数据
    reset() {
      ...
      this.showUploadList = false;
      this.uploadList = [];
      this.pid = 0;
      this.state = 0;
      ...
    },
    //提交
    submit() {
      const flag = this.validInput();
      if (flag) {
           //另起对象,防止改到视图
        const param = JSON.parse(JSON.stringify(this.resultForm));
        //调用接口
      }
    },

    //验证数据
    validInput() {
      //验证数据,且将有效值赋值给form
      return true;
    },

    //删除文件
    deleteFile(index) {
      this.$confirm(`是否确定删除"${this.uploadList[index].name}"`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.uploadList.splice(index, 1);
          this.fileList.splice(index, 1);
        })
        .catch(err => {
          console.log(err);
        });
    },

    //上传成功
    uploadFile(res, file, fileList) {
      this.fileList = fileList;
      if (file && file.status === "success") {
        let flag = false;
        this.uploadList.forEach(item => {
          if (item.name === file.name) flag = true;
        });
        if (flag) {
          this.$message({
            message: `已存在${file.name}`,
            type: "error"
          });
          return;
        }
        //注意判重
        if (!flag && file.response) {
          this.uploadList.push({
            name: file.name,
            url: this.host + file.response.data,
            upload: file.name + "," + file.response.data
          });
        }
        this.$message({
          type: "success",
          message: "上传成功"
        });
      }
    },

    //获取当前状态
    getNowStatus(id) {
      id = parseInt(id);
      getStateByID(id)
        .then(res => {
          if (res.success) {
            if (res.data && res.data.length > 0) {
              let company = res.data[0];
              this.pid = parseInt(company.id);
              this.state = company.state;
              //...
            } else {
              this.pid = 0;
            }
            if (this.pid && this.pid !== 0) {
              //if (某个状态)
                this.getData(this.pid);
            } else {
              this.reset();
            }
          } else {
            this.$message({
              type: "error",
              message: res.message
            });
          }
        })
        .catch(err => {
          this.$message({
            type: "error",
            message: err.message
          });
        });
    },

    //获取\信息
    getData(pid) {
      getByPid(pid)
        .then(res => {
          if (res.success) {
            let result = res.data;
            //附件的处理
            this.uploadList = result.fileList
              .split("|")
              .reduce((prev, curr) => {
                let [name, localurl] = curr.split(",");
                prev.push({
                  name: name,
                  url: this.host + localurl,
                  upload: name + "," + localurl
                });
                return prev;
              }, []);
            ...
              //其他地方赋值
          } else {
            //失败逻辑
          }
        })
        .catch(err => {
          //异常逻辑
        });
    }
  }
};
</script>

  最后,只要在退出登录的地方使用sessionStorage.removeItem('state'+id)防止出现其他问题即可

  以上是本人在这类问题上比较直观的解决方法,如果有更好的或者更高效的解决方法,欢迎评论区留言指教,不胜感激。

  • alipay
  • wechat