vue 프로젝트가 메뉴 권한을 수행할 때 동적 라우팅에 무한 루프 문제가 있고 페이지 저장소 데이터를 새로 고치는 문제가 손실되고 페이지가 비어 있습니다.

최근 프로젝트에서 요구하는 메뉴권한, 버튼권한 등을 vue로 개발하였습니다.먼저 아래 그림과 같이 프로젝트 배경의 페이지 스타일을 살펴보겠습니다. 관리, 메뉴 관리 및 역할 관리. 사용자 관리는 이름에서 알 수 있듯이 계정 추가, 계정 수정, 비활성화 및 활성화 등과 같은 몇 가지 일반적인 기능을 포함하여 시스템을 사용하는 사람을 관리하는 것입니다. 우리 시스템에는 통합된 로그인 암호가 있으므로 입력할 필요가 없습니다. 계정 추가 시 비밀번호 항목은 개인센터에서 개인정보를 조회하여 휴대폰 번호와 로그인 비밀번호를 변경할 수 있습니다. 이러한 구현은 어렵지 않으며 인터페이스를 조정하여 추가, 삭제, 수정 및 확인하고 비즈니스 로직 코드를 작성하십시오.

사용자 관리 및 개인 센터 모듈

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

메뉴 관리 모듈

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
이 메뉴 관리 모듈은 vue-treeselect 구성 요소를 사용하며 여기에서 코드 이름은 라우팅 구성 요소의 이름 또는 페이지의 메뉴 권한 또는 버튼 권한에 고유하고 바인딩되는 버튼의 고유 식별자입니다.부모는 vue-treeselect 구성 요소를 사용하여 현재 디렉토리 또는 버튼의 부모. 이 구성 요소에 익숙하지 않은 경우 vue-treeselect 공식 웹 사이트 로 이동 하여 먼저 npm install --save @riophae/vue-treeselect를 주문하여 설치한 다음 사용하기 전에 가져오기 및 등록하고 코드를 붙여넣을 수 있습니다.

//安装
npm install --save @riophae/vue-treeselect
//引入
  import Treeselect from '@riophae/vue-treeselect'
  // import the styles
  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  //注册局部组件
  components: {
    
     Treeselect },
<template>
  <div class="app-container">
    <div style="margin-top: 10px">
      <el-input
        v-model="search"
        placeholder="输入权限名称进行搜索"
        style="width: 200px"
        class="filter-item"
        @keyup.native="handleFilter"
      />

      <!-- :disabled="!$checkPermission(['menu_add'])" -->
      <el-button
        type="primary"
        icon="el-icon-plus"
        :disabled="!$checkPermission(['menu_add'])"
        @click="handleAdd"
        >新增</el-button
      >
    </div>
    <el-table
      v-loading="listLoading"
      :data="
        tableData.filter(
          data =>
            !search || data.name.toLowerCase().includes(search.toLowerCase())
        )
      "
      style="width: 100%; margin-top: 10px"
      border
      fit
      stripe
      highlight-current-row
      max-height="600"
      row-key="id"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column label="菜单名称">
        <template slot-scope="scope">{
    
    {
    
     scope.row.name }}</template>
      </el-table-column>
      <el-table-column label="类型">
        <template slot-scope="scope">{
    
    {
    
     TypeWays(scope.row.type) }}</template>
      </el-table-column>
      <el-table-column label="代号">
        <template slot-scope="scope">{
    
    {
    
     scope.row.url }}</template>
      </el-table-column>
      <el-table-column label="排序">
        <template slot-scope="scope">{
    
    {
    
     scope.row.status }}</template>
      </el-table-column>
      <el-table-column align="center" label="操作" width="170">
        <template slot-scope="scope">
          <el-button
            type="primary"
            :disabled="!$checkPermission(['menu_edit'])"
            size="small"
            @click="handleEdit(scope)"
            >编辑</el-button
          >

          <el-button
            type="danger"
            size="small"
            :disabled="!$checkPermission(['menu_delete'])"
            @click="handleDelete(scope)"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>

    <el-dialog
      :visible.sync="dialogVisible"
      :title="dialogType === 'edit' ? '编辑' : '新增'"
    >
      <el-form
        ref="Form"
        :model="perm"
        label-width="80px"
        label-position="right"
        :rules="rule1"
      >
        <el-form-item label="类型">
          <el-radio-group v-model="perm.type" @change="typeChange">
            <el-radio :label="1">目录</el-radio>
            <el-radio :label="2">按钮</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="名称" prop="name">
          <el-input v-model="perm.name" placeholder="名称" />
        </el-form-item>
        <el-form-item label="代号" prop="url">
          <el-input v-model="perm.url" placeholder="代号" />
        </el-form-item>
        <el-form-item label="父级" prop="pid">
          <treeselect
            v-model="perm.pid"
            :multiple="false"
            :options="TreeData"
            placeholder="父级"
            :normalizer="normalizer"
          />
        </el-form-item>
        <el-form-item label="排序" prop="status">
          <el-input-number
            v-model="perm.status"
            :min="1"
            label="排序"
          ></el-input-number>
        </el-form-item>

        <el-form-item label="备注" prop="remarks">
          <el-input
            type="textarea"
            :rows="2"
            placeholder="请输入备注"
            v-model="perm.remarks"
          >
          </el-input>
        </el-form-item>
      </el-form>
      <div style="text-align: right">
        <el-button type="danger" @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmPerm('Form')">确认</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// import { getPermAll, createPerm, deletePerm, updatePerm } from "@/api/perm";
import * as user from "@/api/datax-user";
import {
    
    
  menuList,
  menuSaveForm,
  menuDetail,
  menuEdit,
  menuDelete,
  menuGetTree,
  menuGetTreeNotBtn
} from "@/api/datax-menu";

import {
    
     genTree, genTree2 } from "@/utils";

import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
const defaultPerm = {
    
    
  id: null,
  name: "",
  type: 1,
  url: "",
  status: 1,
  c: null,
  remarks: "",
  icon: ""
};
export default {
    
    
  components: {
    
     Treeselect },
  data() {
    
    
    return {
    
    
      perm: defaultPerm,
      search: "",
      tableData: [],
      TreeData: [],
      permList: [],
      listLoading: true,
      dialogVisible: false,
      dialogType: "new",
      rule1: {
    
    
        name: [{
    
     required: true, message: "请输入名称", trigger: "blur" }],
        url: [{
    
     required: true, message: "请输入代号", trigger: "blur" }]
      },
      normalizer(node) {
    
    
        if (node.childList && !node.childList.length) {
    
    
          delete node.childList;
        }

        return {
    
    
          id: node.id,
          pid: node.pid,
          value: node.id,
          label: node.name,
          name: node.name,
          children: node.childList
        };
      }
    };
  },
  computed: {
    
    },
  created() {
    
    
    this.getList();
  },
  methods: {
    
    
    getList() {
    
    
      this.listLoading = true;
      menuList({
    
    
        current: 1,
        size: 1000000,
        name: this.search,
        status: "",
        type: ""
      }).then(response => {
    
    
        console.log("菜单列表", response);
        if (response.code == 200) {
    
    
          this.permList = response.content.listpg;
          const data = genTree(response.content.listpg);
          this.tableData = data;
          this.listLoading = false;
        }
      });
    },

    traversalTree(arrs, result) {
    
    
      arrs.map((item, index) => {
    
    
        let obj = {
    
    
          key: item.id,
          title: item.name,
          children: []
        };
        result.push(obj);
        obj.children = obj.childList;

        if (item.childList.length !== 0) {
    
    
          traversalTree(item.childList, result[index].children);
        }
      });
    },

    //获取菜单树不包含按钮
    getTreeList() {
    
    
      menuGetTreeNotBtn({
    
    
        type: 0
      })
        .then(res => {
    
    
          this.TreeData = res.content;
        })
        .catch(err => {
    
    });
    },
    resetFilter() {
    
    
      this.getList();
    },
    handleFilter() {
    
    
      const newData = this.permList.filter(
        data =>
          !this.search ||
          data.name.toLowerCase().includes(this.search.toLowerCase())
      );
      this.tableData = genTree(newData);
    },
    handleAdd() {
    
    
      this.getTreeList();
      this.perm = Object.assign({
    
    }, defaultPerm);
      this.dialogType = "new";
      this.dialogVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs["Form"].clearValidate();
      });
    },
    handleEdit(scope) {
    
    
      // console.log("点了编辑", scope);
      this.getTreeList();
      var dataT = JSON.parse(JSON.stringify(scope.row));
      this.perm = Object.assign({
    
    }, dataT); // copy obj

      if (scope.row.pid == 0) {
    
    
        this.perm.pid = null;
      }
      this.dialogType = "edit";
      this.dialogVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs["Form"].clearValidate();
      });
    },
    handleDelete(scope) {
    
    
      this.$confirm("确认删除?", "警告", {
    
    
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "error"
      })
        .then(async () => {
    
    
          await menuDelete(scope.row);
          this.getList();
          this.getTreeList();
          this.$message({
    
    
            type: "success",
            message: "成功删除!"
          });
        })
        .catch(err => {
    
    
          console.error(err);
        });
    },
    async confirmPerm(form) {
    
    
      this.$refs[form].validate(valid => {
    
    
        if (valid) {
    
    
          const isEdit = this.dialogType === "edit";
          if (isEdit) {
    
    
            this.perm.children = [];
            console.log("编辑入参", this.perm);
            menuEdit(this.perm).then(() => {
    
    
              this.getList();
              this.dialogVisible = false;
              this.$message({
    
    
                message: "编辑成功",
                type: "success"
              });
            });
          } else {
    
    
            let addParams = {
    
    
              ...this.perm,
              pid: !this.perm.pid ? 0 : this.perm.pid
            };

            if (addParams.hasOwnProperty("id")) {
    
    
              delete addParams.id;
            }

            // console.log("新增入参", addParams);

            menuSaveForm(addParams).then(res => {
    
    
              // this.perm = res.data
              // this.tableData.unshift(this.perm)
              this.getList();
              this.dialogVisible = false;
              this.$message({
    
    
                message: "新增成功",
                type: "success"
              });
            });
          }
        } else {
    
    
          return false;
        }
      });
    },

    TypeWays(type) {
    
    
      if (type == 1) {
    
    
        return "目录";
      } else if (type == 2) {
    
    
        return "按钮";
      }
    },
    typeChange(val) {
    
    
      this.perm.pid = null;
    }
  }
};
</script>

역할 관리 모듈

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
우리의 역할 관리에는 이 네 가지 역할만 있고 우리의 버튼 권한은 역할을 만들 때 메뉴 디렉터리에서 틱으로 구성됩니다.

<template>
  <!-- 角色列表 -->
  <div class="app-container">
    <div class="filter-container">
      <el-input
        v-model.trim="listQuery.name"
        placeholder="角色名称"
        style="width: 200px;"
        class="filter-item"
        clearable
      />
      <!-- <el-input
        v-model.trim="listQuery.roleId"
        placeholder="角色ID"
        style="width: 200px;"
        class="filter-item"
      /> -->

      <el-button
        v-waves
        class="filter-item"
        type="primary"
        icon="el-icon-search"
        @click="fetchData"
      >
        搜索
      </el-button>
      <el-button
        class="filter-item"
        style="margin-left: 0px;"
        type="primary"
        icon="el-icon-plus"
        :disabled="!$checkPermission(['role_add'])"
        @click="handleCreate"
      >
        添加
      </el-button>
    </div>
    <div class="cardWhite">
      <el-table
        v-loading="listLoading"
        :data="list"
        element-loading-text="Loading"
        :border="border"
        fit
        highlight-current-row
      >
        <el-table-column align="left" label="序号" width="95">
          <template slot-scope="scope">{
    
    {
    
     scope.$index + 1 }}</template>
        </el-table-column>
        <el-table-column label="角色名称" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.name }}</template>
        </el-table-column>

        <el-table-column label="创建时间" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.createTime }}</template>
        </el-table-column>

        <el-table-column label="修改时间" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.modifyTime }}</template>
        </el-table-column>

        <el-table-column label="角色是否启用" align="left">
          <template slot-scope="scope">
            <span>{
    
    {
    
     scope.row.status == 1 ? "启用" : "禁用" }}</span>
          </template>
        </el-table-column>

        <el-table-column label="备注" align="left">
          <template slot-scope="scope">
            <span>{
    
    {
    
     scope.row.remarks }}</span>
          </template>
        </el-table-column>

        <el-table-column
          label="操作"
          align="left"
          width="180"
          class-name="small-padding fixed-width"
        >
          <template slot-scope="{ row }">
            <el-button
              type="primary"
              size="mini"
              @click="handleUpdate(row)"
              :disabled="!$checkPermission(['role_edit'])"
            >
              编辑
            </el-button>
            <el-button
              size="mini"
              type="danger"
              @click="handleDelete(row)"
              :disabled="!$checkPermission(['role_delete'])"
            >
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <pagination
      v-show="total > 0"
      :total="total"
      :page.sync="listQuery.current"
      :limit.sync="listQuery.size"
      @pagination="fetchData"
    />

    <el-dialog
      :title="textMap[dialogStatus]"
      :visible.sync="dialogFormVisible"
      :close-on-click-modal="false"
      width="800px"
    >
      <el-form
        ref="dataForm"
        :rules="rules"
        :model="temp"
        label-position="right"
        label-width="160px"
      >
        <el-row>
          <el-col :span="12" :pull="1">
            <el-form-item label="角色名称" prop="name">
              <el-input v-model.trim="temp.name" placeholder="请输入角色名称" />
            </el-form-item>
            <el-form-item label="角色类型" prop="systemAdmin">
              <el-select
                v-model="temp.systemAdmin"
                class="filter-item"
                placeholder="角色类型"
                style="width:100%"
              >
                <el-option key="超级管理员" label="超级管理员" :value="1" />
                <el-option key="审计员" label="审计员" :value="2" />
                <el-option key="操作员" label="操作员" :value="3" />
                <el-option key="管理员" label="管理员" :value="4" />
              </el-select>
            </el-form-item>

            <el-form-item label="角色是否启用" prop="status">
              <el-select
                v-model="temp.status"
                class="filter-item"
                placeholder="角色是否启用"
                style="width:100%"
              >
                <el-option key="启用" label="启用" :value="1" />
                <el-option key="禁用" label="禁用" :value="2" />
              </el-select>
            </el-form-item>

            <el-form-item label="备注" prop="remarks">
              <el-input v-model.trim="temp.remarks" placeholder="请输入备注" />
            </el-form-item>
          </el-col>

          <el-col :span="12" :pull="1">
            <el-form-item label="菜单目录" prop="menuList">
              <!-- :default-checked-keys="temp.menuList" -->
              <el-tree
                :data="treeData"
                show-checkbox
                :check-strictly="true"
                ref="treeRef"
                node-key="id"
                :props="defaultProps"
                :default-checked-keys="defaultCheckedKeys"
                @check="checkTree"
              >
              </el-tree>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">
          取消
        </el-button>
        <el-button
          type="primary"
          @click="dialogStatus === 'create' ? createData() : updateData()"
        >
          确定
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import * as user from "@/api/datax-user";
import * as api from "@/api/datax-role.js";
import * as apiMenu from "@/api/datax-menu";

import waves from "@/directive/waves"; // waves directive
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination

export default {
    
    
  name: "User",
  components: {
    
     Pagination },
  directives: {
    
     waves },
  filters: {
    
    
    statusFilter(status) {
    
    
      const statusMap = {
    
    
        published: "success",
        draft: "gray",
        deleted: "danger"
      };
      return statusMap[status];
    }
  },
  data() {
    
    
    return {
    
    
      list: null,
      listLoading: true,
      total: 0,
      listQuery: {
    
    
        current: 1,
        size: 10,
        name: "",
        status: "",
        type: ""
      },
      roles: ["ROLE_USER", "ROLE_ADMIN"],
      dialogPluginVisible: false,
      pluginData: [],
      dialogFormVisible: false,
      dialogStatus: "",
      textMap: {
    
    
        update: "编辑角色",
        create: "创建角色"
      },
      rules: {
    
    
        name: [{
    
     required: true, message: "请输入角色名称", trigger: "blur" }],
        systemAdmin: [
          {
    
    
            required: true,
            message: "请选择角色类型",
            trigger: "change"
          }
        ],
        status: [
          {
    
     required: true, message: "请选择角色是否启用", trigger: "change" }
        ],
        remarks: [{
    
     required: false, message: "请输入备注", trigger: "blur" }],
        menuList: [
          {
    
     required: false, message: "请选择菜单列表", trigger: "change" }
        ]
      },
      temp: {
    
    
        name: "",
        systemAdmin: 1,
        status: 1,
        remarks: "",
        menuList: []
      },
      resetTemp() {
    
    
        this.temp = this.$options.data().temp;
      },
      border: window.g.borderFlag,
      selectList: [],
      treeData: [],
      defaultProps: {
    
    
        children: "childList",
        label: "name"
      },
      defaultCheckedKeys: []
    };
  },
  created() {
    
    
    this.getMenuList();
    this.fetchData();
  },
  methods: {
    
    
    getMenuList() {
    
    
      apiMenu
        .menuGetTree()
        .then(response => {
    
    
          console.log("菜单树", response);
          this.treeData = response.content;

          // this.listLoading = false;
        })
        .catch(err => {
    
    
          // this.listLoading = false;
        });
    },
    fetchData() {
    
    
      this.listLoading = true;
      api
        .roleList(this.listQuery)
        .then(response => {
    
    
          // console.log("角色列表", response);
          const {
    
     content } = response;
          this.total = content.totalResult;
          this.list = content.listpg;
          this.listLoading = false;
        })
        .catch(err => {
    
    });
    },
    handleCreate() {
    
    
      this.resetTemp();

      this.dialogStatus = "create";
      this.dialogFormVisible = true;
      this.$nextTick(() => {
    
    
        this.defaultCheckedKeys = [];
        this.$refs.treeRef.setCheckedKeys([]);
        this.$refs["dataForm"].clearValidate();
      });
    },
    createData() {
    
    
      if (this.temp.menuList.length <= 0) {
    
    
        this.$notify({
    
    
          title: "提示",
          message: "请先选择菜单后再提交",
          type: "error",
          duration: 2000
        });
        return false;
      }
      this.$refs["dataForm"].validate(valid => {
    
    
        if (valid) {
    
    
          api.roleSaveForm(this.temp).then(() => {
    
    
            this.fetchData();
            this.dialogFormVisible = false;
            this.$notify({
    
    
              title: "完成",
              message: "创建成功",
              type: "success",
              duration: 2000
            });
          });
        }
      });
    },
    handleUpdate(row) {
    
    
      // this.temp = Object.assign({}, row); // copy obj
      this.dialogStatus = "update";
      this.defaultCheckedKeys = [];

      this.dialogFormVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs.treeRef.setCheckedKeys([]);
        this.$refs["dataForm"].clearValidate();
      });

      let obj = {
    
    
        id: row.id
      };
      api
        .roleDetail(obj)
        .then(res => {
    
    
          this.temp = res.content ? res.content : {
    
    };
          this.defaultCheckedKeys = res.content.menuList;
          // console.log("角色详情", this.defaultCheckedKeys);
        })
        .catch(() => {
    
    });
    },
    updateData() {
    
    
      if (this.temp.menuList.length <= 0) {
    
    
        this.$notify({
    
    
          title: "提示",
          message: "请先选择菜单后再提交",
          type: "error",
          duration: 2000
        });
        return false;
      }
      this.$refs["dataForm"].validate(valid => {
    
    
        if (valid) {
    
    
          const tempData = Object.assign({
    
    }, this.temp);
          api.roleEdit(tempData).then(() => {
    
    
            this.fetchData();
            this.dialogFormVisible = false;
            this.$notify({
    
    
              title: "完成",
              message: "编辑成功",
              type: "success",
              duration: 2000
            });
          });
        }
      });
    },
    handleDelete(row) {
    
    
      this.$confirm("确定删除这条数据吗", "提示", {
    
    
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
    
    
          api.roleDelete(row).then(response => {
    
    
            this.fetchData();
            this.$notify({
    
    
              title: "完成",
              message: "删除成功",
              type: "success",
              duration: 2000
            });
          });
        })
        .catch(() => {
    
    });
    },

    checkTree(node, data) {
    
    
      console.log("role的checkTree", node, data);
      this.temp.menuList = data.checkedKeys;
    }
  }
};
</script>

동적 라우팅 구성

앞에서 사용자 관리, 메뉴 관리, 역할 관리에 대해 설명했습니다.이것들은 모두 비즈니스 코드이므로 큰 문제가 아닙니다.이제 다른 역할에 따라 시스템에 로그인하여 다른 측면 탐색 메뉴를 본 다음 다른 역할을 볼 수 있습니다. 다른 버튼 권한을 가질 수 있습니다. 여기에서 함께 알아봅시다. 로그인 인터페이스에 사용자 이름과 암호를 입력한 후 로그인에 성공한 후 백엔드는 현재 역할이 소유한 메뉴 권한 집합과 버튼 권한 집합을 프런트 엔드로 반환합니다.예를 들어 관리자로 로그인했습니다. admin 계정, 메뉴 권한에는 menuList: ["home ", "system", "user", "menu", "role"] 버튼 권한에는 btnList: ["user_add", "user_edit", "user_delete"]가 있습니다. 로컬 라우팅은 다음과 같습니다. 전체 코드는 다음과
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
같습니다
여기에 이미지 설명 삽입
.

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'
import LayoutEx from '@/layoutEx'

var showAgent = window.g.showAgent
/* Router Modules */

import toolRouter from './modules/tool'


//===固定路由===
export const constantRoutes = [
  {
    
    
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
    
    
        path: '/redirect/:path*',
        component: () => import('@/views/redirect/index'),
      },
    ],
  },
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true,
  },
  {
    
    
    path: '/auth-redirect',
    component: () => import('@/views/login/auth-redirect'),
    hidden: true,
  },
  {
    
    
    path: '/404',
    component: () => import('@/views/error-page/404'),
    hidden: true,
  },
  {
    
    
    path: '/401',
    component: () => import('@/views/error-page/401'),
    hidden: true,
  },
  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [
      // {
    
    
      //   path: 'dashboard',
      //   component: () => import('@/views/dashboard/admin/index'),
      //   name: '首 页',
      //   meta: { title: '首页', icon: 'el-icon-s-home', affix: true }
      // },
      {
    
    
        path: 'dashboard',
        component: () => import('@/views/homePage/index'),
        // name: '首 页',
        name: 'HomePage',
        meta: {
    
     title: '首页', icon: 'el-icon-s-home' },
      },
    ],
  }
 
]
//===动态路由 menuName就是前端页面配置菜单里的代号,要保持一致===
export const asyncRoutes = [

  {
    
    
    path: '/datax/project',
    component: Layout,
    redirect: '/datax/project/jobProject',
    name: 'datasource',
    meta: {
    
    
      title: '任务组管理',
      icon: 'el-icon-s-grid',
      menuName: 'datasource',
    },
    children: [
      {
    
    
        path: 'jobProject',
        name: 'jobProject',
        component: () => import('@/views/datax/jobProject/index'),
        meta: {
    
    
          title: '任务组管理',
          icon: 'el-icon-s-grid',
          menuName: 'jobProject',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/job',
    component: Layout,
    redirect: '/datax/job/jobInfo',
    name: 'job',
    meta: {
    
     title: '任务管理', icon: 'el-icon-set-up', menuName: 'job' },
    children: [
      {
    
    
        path: 'jobInfo',
        name: 'JobInfo',
        component: () => import('@/views/datax/jobInfo/fileJob'),
        meta: {
    
    
          title: '文件任务',
          icon: 'el-icon-set-up',
          menuName: 'JobInfo',
        },
      },
      {
    
    
        path: 'missionData',
        name: 'missionData',
        component: () => import('@/views/datax/jobInfo/dataJob'),
        meta: {
    
    
          title: '数据库任务',
          icon: 'el-icon-set-up',
          menuName: 'missionData',
        },
      },
      {
    
    
        path: 'jsonBuild',
        name: 'JsonBuild',
        hidden: true,
        component: () => import('@/views/datax/json-build/index'),
        meta: {
    
    
          title: '任务构建',
          icon: 'guide',
          noCache: false,
          menuName: 'jsonBuild',
        },
      },
      {
    
    
        path: 'jsonBuildBatch',
        name: 'JsonBuildBatch',
        hidden: true,
        component: () => import('@/views/datax/json-build-batch/index'),
        meta: {
    
    
          title: '任务批量构建',
          icon: 'batch-create',
          noCache: false,
          menuName: 'jsonBuildBatch',
        },
      },
      {
    
    
        path: 'jobTemplate',
        name: 'JobTemplate',
        hidden: true,
        component: () => import('@/views/datax/jobTemplate/index'),
        meta: {
    
    
          title: 'DataX任务模板',
          icon: 'task-tmp',
          menuName: 'jobTemplate',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/datasource',
    component: Layout,
    redirect: '/datax/datasource/fileDatasource',
    name: 'datasource',
    meta: {
    
     title: '资源管理', icon: 'el-icon-files', menuName: 'datasource' },
    children: [
      {
    
    
        path: 'fileDatasource',
        name: 'fileDatasource',
        component: () => import('@/views/datax/jdbc-datasource/fileControl'),
        meta: {
    
    
          title: '文件资源',
          icon: 'el-icon-files',
          menuName: 'fileDatasource',
        },
      },
      {
    
    
        path: 'jdbcDatasource',
        name: 'JdbcDatasource',
        component: () => import('@/views/datax/jdbc-datasource/dataControl'),
        meta: {
    
    
          title: '数据库资源',
          icon: 'el-icon-files',
          menuName: 'jdbcDatasource',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/jobLog',
    component: Layout,
    redirect: '/datax/jobLog/jobLog',
    name: 'log',

    meta: {
    
     title: '日志管理', icon: 'el-icon-date', menuName: 'log' },
    children: [
      {
    
    
        path: 'jobLog',
        name: 'JobLog',
        component: () => import('@/views/datax/jobLog/index'),
        meta: {
    
    
          title: '业务日志管理',
          icon: 'el-icon-date',
          menuName: 'JobLog',
        },
      },
      {
    
    
        path: 'auditLog',
        name: 'auditLog',
        component: () => import('@/views/datax/jobLog/auditLog'),
        meta: {
    
    
          title: '审计日志管理',
          icon: 'el-icon-date',
          menuName: 'auditLog',
        },
      },

      {
    
    
        path: 'normalLog',
        name: 'normalLog',
        component: () => import('@/views/datax/jobLog/normalLog'),
        meta: {
    
     title: '日志', icon: 'el-icon-date', menuName: 'normalLog' },
      },
    ],
  },
  {
    
    
    path: '/datax/executor',
    component: Layout,
    redirect: '/datax/executor/executor',
    name: 'executor',
    meta: {
    
    
      title: '链路管理',
      icon: 'el-icon-set-up',
      menuName: 'executorManage',
    },
    children: [
      {
    
    
        path: 'executor',
        name: 'Executor',
        component: () => import('@/views/datax/executor/index'),
        // meta: { title: '链路管理', icon: 'exe-cfg' },
        meta: {
    
    
          title: '链路管理',
          icon: 'el-icon-set-up',
          menuName: 'Executor',
        },
      },
    ],
  },
  {
    
    
    path: '/service/exchangeTask',
    component: Layout,
    redirect: '/service/exchangeTask/index',
    name: 'exchangeTask',

    meta: {
    
    
      title: '服务请求交换管理',
      icon: 'el-icon-date',
      menuName: 'exchangeTaskManage',
    },
    children: [
      {
    
    
        path: 'exchangeTask',
        name: 'exchangeTask',
        component: () => import('@/views/service/exchangeTask/index'),
        meta: {
    
    
          title: '交换任务管理',
          icon: 'el-icon-date',
          menuName: 'exchangeTask',
        },
      },
      {
    
    
        path: 'exchangeLog',
        name: 'exchangeLog',
        component: () => import('@/views/service/exchangeLog/index'),
        meta: {
    
    
          title: '交换日志管理',
          icon: 'el-icon-date',
          menuName: 'exchangeLog',
        },
      },

      {
    
    
        path: 'resourcesManage',
        name: 'resourcesManage',
        component: () => import('@/views/service/resourcesManage/index'),
        meta: {
    
    
          title: '资源组管理',
          icon: 'el-icon-date',
          menuName: 'resourcesManage',
        },
      },
      {
    
    
        path: 'visitManage',
        name: 'visitManage',
        component: () => import('@/views/service/visitManage/index'),
        meta: {
    
    
          title: '访问组管理',
          icon: 'el-icon-date',
          menuName: 'visitManage',
        },
      },
      {
    
    
        path: 'limitManage',
        name: 'limitManage',
        component: () => import('@/views/service/limitManage/index'),
        meta: {
    
    
          title: '限制组管理',
          icon: 'el-icon-date',
          menuName: 'limitManage',
        },
      },
      {
    
    
        path: 'boundaryManage',
        name: 'boundaryManage',
        component: () => import('@/views/service/boundaryManage/index'),
        meta: {
    
    
          title: '边界地址管理',
          icon: 'el-icon-date',
          menuName: 'boundaryManage',
        },
      },
    ],
  },

  {
    
    
    path: '/datax/registry',
    component: Layout,
    redirect: '/datax/registry/registry',
    name: 'registry',
    hidden: true,
    meta: {
    
     title: '资源监控', icon: 'work', menuName: 'registryManage' },
    children: [
      {
    
    
        path: 'registry',
        name: 'Registry',
        component: () => import('@/views/datax/registry/index'),
        meta: {
    
     title: '资源监控', icon: 'battery-line', menuName: 'registry' },
      },
    ],
  },
  {
    
    
    path: '/system',
    component: Layout,
    redirect: '/system/user/index',

    meta: {
    
     title: '用户中心', icon: 'el-icon-date', menuName: 'system' },
    children: [
      {
    
    
        path: '/user',
        name: 'user',
        component: () => import('@/views/system/user/index'),
        meta: {
    
     title: '用户管理', icon: 'el-icon-s-custom', menuName: 'user' },
      },
      {
    
    
        path: 'menu',
        name: 'menu',
        component: () => import('@/views/system/menu/index'),
        meta: {
    
     title: '菜单管理', icon: 'el-icon-menu', menuName: 'menu' },
      },
      {
    
    
        path: 'role',
        name: 'role',
        component: () => import('@/views/system/role/index'),
        meta: {
    
     title: '角色管理', icon: 'el-icon-menu', menuName: 'role' },
      },
      {
    
    
        path: 'personal',
        name: 'personal',
        hidden: true,
        component: () => import('@/views/system/personal/index'),
        meta: {
    
     title: '个人中心', icon: 'el-icon-menu', menuName: 'personal' },
      },
    ],
  },

 

  {
    
     path: '*', redirect: '/404', hidden: true },
]

const createRouter = () =>
  new Router({
    
    
    // mode: 'history', // require service support
    scrollBehavior: () => ({
    
     y: 0 }),
    routes: constantRoutes.concat(asyncRoutes),
  })

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

내 로그인 방법은 저장소에 작성되어 있기 때문에 로그인에 성공한 후 일부 데이터를 로컬에 캐시합니다. 예를 들어 사용자 이름과 사용자 ID를 여기에 캐시한 다음 상태에서 토큰과 이름을 변경하고 commit 메소드를 통한 현재 역할 수집 역할, 디스패치를 ​​통해 액세스 가능한 라우팅 테이블을 생성하고 권한 모듈 아래의 작업에서 비동기 메소드 generateRoutesMe를 트리거합니다.generateRoutesMe 메소드에서 다른 메소드 filterAsyncRoutes를 사용하여 로컬 경로를 처리합니다.메뉴 권한이 있는 경우 list set menuList는 로컬과 관련이 있습니다. 경로의 menuName이 일치하면 해당 메뉴를 false로 설정하여 메뉴가 표시되고 권한이 있음을 나타냅니다. 그렇지 않으면 허가 없이 true로 설정되어 표시되지 않습니다. 버튼 권한은 훨씬 더 간단합니다.버튼 권한 설정 btnList를 얻은 후 모듈의 버튼은 전역 공용 메서드 확인 권한을 통해 처리되고 지정된 코드 매개 변수를 전달합니다.이 매개 변수는 페이지에서 구성한 코드입니다.우리는 버튼 버튼의 권한에는 두 가지 효과가 있습니다. 권한이 없으면 클릭할 수 없거나 권한 없이 표시되지 않습니다. 코드는 다음과 같습니다. 우리가 페이지에 구성한 코드 버튼 버튼에 대한 권한을 설정하고 표시할 두 가지 효과가 있습니다. 권한이 없으면 클릭할 수 없거나 권한 없이 표시되지 않습니다. 코드는 다음과 같습니다. "!권한 확인 하고 지정된 코드 매개 변수 를 프로세스에 전달합니다 . 이 매개변수는 페이지 에서 구성한 코드 입니다 . 버튼 버튼 대한 권한을 설정하면 두 가지 효과가 있습니다.만약 권한이 없으면 클릭할 수 없거나 권한이 없으면 바로 표시되지 않습니다.코드는 다음과 같습니다.:장애 _ _ _ _ _ _=" ! checkPermission(['user_add'])" 또는 v-show="!$checkPermission(['user_add'])". 이것이 메뉴 권한과 버튼 권한의 개념입니다.아래 코드를 붙여넣으십시오:
utils 디렉토리 아래의 permission.js에서 전역 공용 메서드 checkPermission을 캡슐화한 다음 이를 main.js로 가져와서 프로토타입에 마운트하여 다음과 같이 전역적으로 사용할 수 있습니다. 그림:
여기에 이미지 설명 삽입여기에 이미지 설명 삽입
코드는 다음과 같습니다.

//=====utils目录下的permission.js里=====
import store from '@/store'

/**
 * @param {Array} value
 * @returns {Boolean}
 * @example see @/views/permission/directive.vue
 */
export default function checkPermission(value) {
    
    
  if (value && value instanceof Array && value.length > 0) {
    
    
    const roles = store.getters && store.getters.roles
    const permissionRoles = value
    // console.log('验证按钮权限', store, roles, permissionRoles)
    const hasPermission = roles.some((role) => {
    
    
      return permissionRoles.includes(role)
    })

    if (!hasPermission) {
    
    
      return false
    } else {
    
    
      return true
    }
  } else {
    
    
    console.error(`need roles! Like v-permission="['admin','editor']"`)
    return false
  }
}

//=========main.js里=========
//将验证按钮权限的方法挂载到this以便全局使用
import checkPermission from './utils/permission.js'
Vue.prototype.$checkPermission = checkPermission


store 디렉토리의 index.js 코드는
다음과 같습니다.
여기에 이미지 설명 삽입

//================store目录下的getters.js代码如下:================
const getters = {
    
    
  sidebar: (state) => state.app.sidebar,
  size: (state) => state.app.size,
  device: (state) => state.app.device,
  visitedViews: (state) => state.tagsView.visitedViews,
  cachedViews: (state) => state.tagsView.cachedViews,
  token: (state) => state.user.token,
  avatar: (state) => state.user.avatar,
  name: (state) => state.user.name,
  introduction: (state) => state.user.introduction,
  roles: (state) => state.user.roles,
  permission_routes: (state) => state.permission.routes,
  addRoutes: (state) => state.permission.addRoutes,
  ifchange: (state) => state.permission.ifchange,
  errorLogs: (state) => state.errorLog.logs,
}
export default getters

//========store目录下的modules里的user.js代码如下:===============
import {
    
     login, logout } from '@/api/user'
import {
    
     menuGetTree } from '@/api/datax-menu'
import {
    
     getToken, setToken, removeToken } from '@/utils/auth'
import router, {
    
     resetRouter } from '@/router'
import store from '../index.js'

const state = {
    
    
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: [],
}

const mutations = {
    
    
  SET_TOKEN: (state, token) => {
    
    
    // console.log('SET_TOKEN', token)
    state.token = token
  },
  SET_INTRODUCTION: (state, introduction) => {
    
    
    state.introduction = introduction
  },
  SET_NAME: (state, name) => {
    
    
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    
    
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    
    
    state.roles = roles
  },
}

const actions = {
    
    
  // user login
  login({
     
      commit }, userInfo) {
    
    
    const {
    
     username, password, code } = userInfo

    return new Promise((resolve, reject) => {
    
    
      login({
    
    
        username: username.trim(),
        password: password,
        // rememberMe: 1,
        code: code,
      })
        .then(async (response) => {
    
    
          console.log('登录进来', response)
          const {
    
     data } = response.content
          const {
    
     roles } = response.content
          commit('SET_TOKEN', response.content.token)
          commit('SET_NAME', response.content.username)
          sessionStorage.setItem('name', response.content.username)

          if (roles) {
    
    
            localStorage.setItem('roles', JSON.stringify(roles))
          }

          setToken(response.content.token)

          //缓存当前角色菜单树
          // sessionStorage.setItem('menuList', response.content.menuList)

          //缓存当前角色拥有的按钮权限集合
          commit('SET_ROLES', response.content.btnList)

          let menuIdArr = response.content.menuList

          //生成可访问的路由表
          const accessRoutes = await store.dispatch(
            'permission/generateRoutesMe',
            menuIdArr,
          )

          // console.log('user的accessRoutes', accessRoutes)
          // store.commit('permission/SET_ROUTES', accessRoutes)

          //缓存修改密码的id
          localStorage.setItem('userId', JSON.stringify(response.content.id))

          resolve()
        })
        .catch((error) => {
    
    
          reject(error)
        })
    })
  },

  // get user info
  getInfo({
     
      commit, state }) {
    
    
    return new Promise((resolve, reject) => {
    
    
      const data = {
    
    }

      try {
    
    
        if (localStorage.getItem('roles')) {
    
    
          data.roles = JSON.parse(localStorage.getItem('roles'))
        }
      } catch (err) {
    
    }

      // console.log('data.roles123', data.roles)
      commit('SET_ROLES', data.roles)
      resolve(data)
    })
  },

  // user logout
  logout({
     
      commit, state }) {
    
    
    return new Promise((resolve, reject) => {
    
    
      logout({
    
    
        username: sessionStorage.getItem('name'),
      })
        .then(() => {
    
    
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_NAME', '')
          removeToken()
          resetRouter()
          resolve()
        })
        .catch((error) => {
    
    
          reject(error)
        })
    })
  },

  // remove token
  resetToken({
     
      commit }) {
    
    
    return new Promise((resolve) => {
    
    
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])

      removeToken()
      resolve()
    })
  },

  // dynamically modify permissions
  changeRoles({
     
      commit, dispatch }, role) {
    
    
    return new Promise(async (resolve) => {
    
    
      const token = role + '-token'

      commit('SET_TOKEN', token)
      setToken(token)

      const {
    
     roles } = await dispatch('getInfo')

      resetRouter()

      // generate accessible routes map based on roles
      const accessRoutes = await dispatch('permission/generateRoutes', roles, {
    
    
        root: true,
      })

      // dynamically add accessible routes
      router.addRoutes(accessRoutes)

      // reset visited views and cached views
      dispatch('tagsView/delAllViews', null, {
    
     root: true })

      resolve()
    })
  },
}

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions,
}

//========store目录下的modules里的permission.js代码如下:===============
import {
    
     asyncRoutes, constantRoutes } from '@/router'
import router from '../../router'
import Layout from '@/layout'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
    
    
  // console.log('hasPermission里', roles, route)
  if (route.meta && route.meta.roles) {
    
    
    if (roles) {
    
    
      return roles.some((role) => route.meta.roles.includes(role))
    } else {
    
    
      return true
    }
  } else {
    
    
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles, menuIdArr) {
    
    
  const res = []

  // console.log('filterAsyncRoutes里', routes, roles, menuIdArr)

  routes.forEach((route) => {
    
    
    const tmp = {
    
     ...route }
    if (hasPermission(roles, tmp)) {
    
    
      if (tmp.children) {
    
    
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    } else {
    
    
      res = routes
    }
  })

  return res
}

export function filterAsyncRoutesMe(routes, menuIdArr) {
    
    
  // console.log(
  //   'filterAsyncRoutesMe里',
  //   routes,
  //   menuIdArr,
  //   Object.prototype.toString.call(menuIdArr),
  // )

  if (Object.prototype.toString.call(menuIdArr) == '[object String]') {
    
    
    menuIdArr = menuIdArr.split(',')
  }
  let data
  var findRoute = function (arr) {
    
    
    data = arr.map((item) => {
    
    
      // console.log('filterAsyncRoutesMe', item)
      let myItem = {
    
    
        ...item,
        hidden:
          (item.meta &&
            Array.isArray(menuIdArr) &&
            menuIdArr.length > 0 &&
            menuIdArr.some((i) => i == item.meta.menuName)) ||
          !item.hasOwnProperty('hidden') ||
          !item.hidden
            ? false
            : true,
        children:
          item.children && item.children.length > 0
            ? findRoute(item.children)
            : [],
      }

      return {
    
    
        ...myItem,
      }
    })

    return data
  }

  let finallyRoutes = findRoute(routes)
  // console.log('finallyRoutes', finallyRoutes)

  return finallyRoutes
}

// const state = {
    
    
//   routes: [],
//   addRoutes: [],
//   ifchange: false,
// }

const state = {
    
    
  routes: constantRoutes,
  addRoutes: [],
  ifchange: false,
}

const mutations = {
    
    
  SET_ROUTES: (state, routes) => {
    
    
    // state.routes = []
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
    // state.routes = [...constantRoutes, ...routes]
    // console.log('pe132321', state.routes)
    // router.addRoutes(routes)
    state.ifchange = true
  },
}

const actions = {
    
    
  generateRoutes({
     
      commit }, roles, menuIdArr) {
    
    
    return new Promise((resolve) => {
    
    
      let accessedRoutes
      // console.log('generateRoutes里', asyncRoutes, roles, menuIdArr)

      if (roles && roles.includes('ROLE_ADMIN')) {
    
    
        accessedRoutes = asyncRoutes || []
      } else {
    
    
        // accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
        let myRoutes = filterAsyncRoutes(asyncRoutes, roles, menuIdArr)
        // console.log('myRoutes', myRoutes)
        accessedRoutes = myRoutes
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  },

  generateRoutesMe({
     
      commit }, menuIdArr) {
    
    
    return new Promise((resolve) => {
    
    
      let accessedRoutes = filterAsyncRoutesMe(asyncRoutes, menuIdArr)

      // console.log('generateRoutesMe里', asyncRoutes, menuIdArr,accessedRoutes)

      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  },
}

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions,
}

그 때 겪었던 문제 중 하나는 라우팅에 무한 루프가 있다는 것이었습니다.
여기에 이미지 설명 삽입

import router from './router'
import store from './store'
import {
    
     Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {
    
     getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({
    
     showSpinner: false }) // NProgress Configuration

const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist

router.beforeEach(async (to, from, next) => {
    
    
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()
  if (hasToken) {
    
    
    if (to.path === '/login') {
    
    
      // if is logged in, redirect to the home page
      next({
    
     path: '/' })
      NProgress.done()
    } else {
    
    
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      // console.log(
      //   'hasRoles看看',
      //   hasRoles,
      //   store,
      //   store.getters.addRoutes,
      //   store.getters.permission_routes,
      //   JSON.parse(localStorage.getItem('MenuPrmStore')),
      // )
      if (hasRoles) {
    
    
        next()
      } else {
    
    
        try {
    
    
          //拉取info信息
          // const { roles } = await store.dispatch('user/getInfo')
          //获取当前角色所拥有的菜单

          // let menuIdArr = await sessionStorage.getItem('menuList')

          // //生成可访问的路由表
          // const accessRoutes = await store.dispatch(
          //   'permission/generateRoutesMe',
          //   menuIdArr,
          // )

          next()

          // console.log('roles4444', menuIdArr, accessRoutes)

          // if (
          //   store.getters.permission_routes.length > 0 ||
          //   to.name != null ||
          //   store.getters.addRoutes.length > 0
          // ) {
    
    
          //   //放行

          //   next()
          // } else {
    
    
          //   //动态添加可访问路由表
          //   store.commit('SET_ROUTES', accessRoutes)
          //   router.addRoutes(accessRoutes)
          //   // next({ ...to, replace: true })

          //   // for (let i = 0; i < accessRoutes.length; i += 1) {
    
    
          //   //   const element = accessRoutes[i]
          //   //   router.addRoute(element)
          //   // }
          //   // router.options.isAddAsyncMenuData = true

          //   next({ ...to, replace: true })
          // }

          // if (!store.getters.ifchange) {
    
    
          //   //动态添加可访问路由表
          //   router.addRoutes(accessRoutes)
          //   // store.commit('SET_ROUTES', accessRoutes)

          //   next({ ...to, replace: true })
          // } else {
    
    
          //   next()
          // }

             //=====直接下面这样addRoutes会死循环=====
          // router.addRoutes(accessRoutes)
          // next()

          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
        } catch (error) {
    
    
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')

          // Message.error(error || 'Has Error')
          Message.error({
    
     message: error || 'Has Error' })

          next(`/login?redirect=${
      
      to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    
    
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
    
    
      // in the free login whitelist, go directly
      next()
    } else {
    
    
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${
      
      to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
    
    
  // finish progress bar
  NProgress.done()
})

처음에 router.addRoutes(accessRoutes)를 직접 사용하고 next( )를 사용하여 놓았기 때문에 당시에 여기서 무한 루프가 발생했습니다. 0보다 크면 addRoutes를 한 번 의미합니다.직접 next() 릴리스, 그렇지 않으면 먼저 accessRoutes를 통과한 다음 하나씩 추가하거나 한 번에 직접 주입하면 결과가 충분하지 않습니다. 그런 다음 변수 ifchange를 정의하려고 합니다. state, false이면 accessRoutes 다음에 next({ ...to , replace: true }), 그렇지 않으면 next()에 의해 해제됩니다. 그러나 최종 결과는 경로를 찾을 수 없거나 무한 루프입니다. 나중에 알고보니 경로 등록시 올바른 경로를 작성하지 않았네요 코드는 다음과 같습니다
여기에 이미지 설명 삽입
경로를 등록할 때 동적 경로 asyncRoutes를 연결해야 합니다 여기서는 고정 경로 경로로 작성했습니다: constantRoutes, 이는 잘못된 것입니다. . 올바른 경로는 다음과 같습니다. constantRoutes.concat(asyncRoutes)

페이지 새로 고침 후 저장소의 데이터 손실 문제 해결

페이지가 새로고침되면 vue 인스턴스가 다시 로드되므로 저장소도 재설정됩니다. store는 로컬 데이터 저장소가 아닌 구성 요소 상태를 저장하는 데 사용됩니다. 따라서 페이지를 새로 고친 후 재설정하지 않으려는 데이터는 로컬 스토리지를 사용하여 스토리지를 사용하십시오. 예를 들어, 이 예에서 페이지를 새로고침하자마자 내 스토어의 메뉴 및 역할 데이터가 손실되고 페이지가 비어 있을 것입니다. App.vue에서 페이지 새로고침을 모니터링하기 위해 beforeunload 이벤트를 직접 추가하고 페이지에 beforeunload 이벤트가 있습니다. 새로 고침 전에 트리거하여 저장소에 데이터를 캐시한 다음 캐시에 데이터가 있는지 판단하고 데이터가 있으면 저장소의 상태에서 데이터를 변경합니다. 코드 다음과 같다:
여기에 이미지 설명 삽입

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
import store from "./store";
export default {
    
    
  name: "App",
  mounted() {
    
    
    var that = this;
    window.onresize = function() {
    
    
      that.$EventBus.$emit("resize");
    };
  },
  created() {
    
    
    this.refresh();
  },
  methods: {
    
    
    //刷新时重新用本地缓存的路由替换之前router里的路由

    refresh() {
    
    
      // console.log(
      //   "store去去去",
      //   store,
      //   JSON.parse(localStorage.getItem("MenuPrmStore"))
      // );
      // console.log("store.state", store.state);

      try {
    
    
        if (localStorage.getItem("MenuPrmStore")) {
    
    
          store.commit(
            "permission/SET_ROUTES",
            JSON.parse(localStorage.getItem("MenuPrmStore"))
          );
        }

        if (localStorage.getItem("roleList")) {
    
    
          store.commit(
            "user/SET_ROLES",
            JSON.parse(localStorage.getItem("roleList"))
          );
        }
      } catch (e) {
    
    
        console.log("刷新出错", e);
      }

      // console.log(
      //   "目前store.state.permission.routes",
      //   store.state.permission.routes
      // );
      // }
      // 在页面刷新时将vuex里的信息保存到localStorage里
      // beforeunload事件在页面刷新之前先触发
      window.addEventListener("beforeunload", () => {
    
    
        //存菜单列表

        localStorage.setItem(
          "MenuPrmStore",
          JSON.stringify(store.state.permission.addRoutes)
        );

        //存角色权限列表
        localStorage.setItem(
          "roleList",
          JSON.stringify(store.state.user.roles)
        );
      });
    }
  }
};
</script>

추천

출처blog.csdn.net/qq_37635012/article/details/127786033