VUE的element动态路由跳转问题

为了防止接口异常,在上一章的基础上创建一个mork文件夹写了个menu.json放入public文件里:

Element官网:https://element.eleme.cn/#/zh-CN/guide/design

{

    "data": [

        {

            "id": 101,

            "authName": "用户管理",

            "path": "users",

            "children": [

                {

                    "id": 1,

                    "authName": "用户列表",

                    "path": "users",

                    "children": []

                },

                {

                    "id": 2,

                    "authName": "添加用户",

                    "path": "addusers",

                    "children": []

                }

            ]

        },

        {

            "id": 102,

            "authName": "分类管理",

            "path": "categories",

            "children": [

                {

                    "id": 1,

                    "authName": "分类列表",

                    "path": "categories",

                    "children": []

                },{

                    "id": 2,

                    "authName": "添加分类",

                    "path": "addcategories",

                    "children": []

                }

            ]

        },

        {

            "id": 103,

            "authName": "商品管理",

            "path": "goods",

            "children": [

                {

                    "id": 1,

                    "authName": "商品列表",

                    "path": "goods",

                    "children": []

                }

            ]

        }

    ],

    "meta": {

        "msg": "获取菜单列表成功",

        "status": 200

    }

}

App.vue里放入路由容器:

<template>

  <div id="app">

    <router-view></router-view>

  </div>

</template>

<style lang="scss">

</style>

view下LoginView.vue:

<template>

    <!-- el-form 组件

    :model="ruleForm" ruleForm是data中定义的存储的是用户名和密码值的对象 通过model传给el-form组件 -->

    <!-- :rules="rules" rules是data中定义的对象目的是校验用户名和密码的规则  -->

    <!-- ref="ruleForm" 咱们可以通过ref来获取el-form组件内部的方法 比如:validate校验方法 resetFields重置方法  -->

    <!-- status-icon 是在表单校验错误的时候 输入框中出现的提示小图标-->

    <!-- label-width="200px" 是用来控制用户名和密码文本的宽度  -->

    <div class="myform">

        <el-form :model="ruleForm"  status-icon :rules="rules" ref="ruleForm" label-width="100px">

            <!-- label 控制输入框的文本  prop="username" 是对应表单域model中的username字段

            规则的名字需要和表单域model中的字段一模一样 -->

            <el-form-item label="用户名" prop="username">

              <!-- v-model 里面对应的是data中的数据 -->

                <el-input v-model="ruleForm.username"></el-input>

            </el-form-item>

            <el-form-item label="密码" prop="password">

              <!-- autocomplete="off" 作用是把输入框的自动提示功能关闭 -->

                <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>

            </el-form-item>

            <el-form-item>

              <!-- 提交的时候把ref里面的名字传过去目的是为了使用refs方法 来调用el-form里面的 validate校验方法-->

                <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>

                <!-- 提交的时候把ref里面的名字传过去目的是为了使用refs方法 来调用el-form里面的 resetFields重置方法-->

                <el-button @click="resetForm('ruleForm')">重置</el-button>

            </el-form-item>

        </el-form>

    </div>


</template>

<script>

import axios from 'axios';

  export default {

    name:"LoginView",

    data() {

      var checkUser = (rule, value, callback) => {


        console.log('用户名:',value)

        if(value.trim()==''){

            callback(new Error('请输入用户名'));

        }else if(!/^[0-9a-zA-Z_\u4e00-\u9fa5@.]{5,12}$/.test(value)){

            callback(new Error('用户名为5-10位中英文数字或者下划线'));

        }

        else{

            callback();

        }

      };

      var validatePass = (rule, value, callback) => {

        console.log('密码:',value)

        if (value.trim()=='') {

          callback(new Error('请输入密码'));

        } else{

          callback();

        }

      };


      return {

        ruleForm: {

          password: '',

          username: ''

        },

        rules: {

          password: [

            { validator: validatePass, trigger: 'blur' }

          ],

          username: [

            { validator: checkUser, trigger: 'blur' }

          ]

        }

      };

    },

    methods: {

      submitForm(formName) {

        this.$refs[formName].validate((valid) => {

          /* el-form组件的validate方法 在回调函数中

           如果 valid 为 true 则表示表单校验通过

           为false则表示不通过 */

          if (valid) {

            axios.post('https://api.***.ed***********',{

              email:this.ruleForm.username,

              password:this.ruleForm.password

            })

            .then(res=>{


              let {access_token} = res.data


                  this.$message.success('登陆成功')

                  /* 当登录成功 把用户名和token存入本地缓存中方便后续使用 */


                  localStorage.token = access_token

                  /* 登录成功后过一秒跳转首页 */

                  setTimeout(()=>{

                    this.$router.push({name:'index'})

                  },1000)

            })

              /* 登录失败(包括用户名或者密码不对会走catch) */

            .catch(()=>{

              this.$message.error('登陆失败')

            })

          } else {

            this.$message.error('您输入的有误')

          }

        });

      },

      resetForm(formName) {

        /* 通过vue中的$refs方法来调用组件el-form中的 resetFields重置方法 */

        this.$refs[formName].resetFields();

      }

    }

  }

</script>

<style lang="scss">

    .myform{

        width:600px;

        margin:50px auto;

    }

</style>

view下IndexView.vue:

//这里做了点改动,相比上一章这里采取动态路由来获取侧边栏以及二级菜单:

相关注意点已用注释表明:

<template>

  <!-- 100vh全屏展示 -->

  <el-container style="height: 100vh; border: 1px solid #eee">

    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">

      <!-- <el-menu :default-openeds="['1', '3']"> 表示默认展开第几个菜单 -->

      <!-- 1对应了el-submenu index="1" -->

      <!-- :default-openeds="openList" 不可以直接['1'] 需要一个变量openList代替

        因为值会变,如果写死 ['1'] 那么就永远不会变

             否则点二级菜单 一级菜单会自动合上-->

      <el-menu

        :default-openeds="openList"

        :router="true"

        :default-active="pagepath"

        :unique-opened="true"

      >

        <!-- :unique-opened="true" 表示始终只打开一个栏点开一个栏另外的会收起来-->

        <!-- default-active="/index/users 表示一进入页面就默认激活/index/users 导航菜单栏 -->

        <!-- 不能写死值,要用监听器解决 -->

        <!-- 把router属性改成true才能实现点击跳转 -->

        <!-- index接收的是字符串类型,(i+1)是数字类型,所以使用toString方法转成字符串,传给index -->

        <!-- 因为i是从0开始的 所以需要+1 -->

        <el-submenu

          :index="(i + 1).toString()"

          v-for="(v, i) in navList"

          :key="i"

        >

          <template slot="title"

            ><i class="el-icon-menu"></i>{{ v.authName }}</template

          >

          <!-- <template slot="title">分组一</template> -->

          <!-- el-menu-item index="1-1" 表示第一个导航里面的第一个子项 -->

          <!-- 子选项需要改成例如: 1-1格式 以字符串的形式传给index属性 -->

          <!-- 因为子选项也是一个数组所以需要再次循环 -->

          <el-menu-item

            :index="'/index/' + item.path"

            v-for="(item, index) in v.children"

            :key="index"

          >

            {{ item.authName }}

          </el-menu-item>

        </el-submenu>

      </el-menu>

    </el-aside>

    <el-container>

      <el-header style="text-align: right; font-size: 12px">

        <el-dropdown>

          <i class="el-icon-setting" style="margin-right: 15px"></i>

          <el-dropdown-menu slot="dropdown">

            <el-dropdown-item>查看</el-dropdown-item>

            <el-dropdown-item>新增</el-dropdown-item>

            <el-dropdown-item>删除</el-dropdown-item>

          </el-dropdown-menu>

        </el-dropdown>

        <span>王小虎</span>

      </el-header>

      <el-main>

        <router-view></router-view>

      </el-main>

    </el-container>

  </el-container>

</template>

<script>

import axios from "axios";

export default {

  data() {

    return {

      openList: ["1"],

      navList: [],

      pagepath: "/index/users",

    };

  },

  watch: {

    /* 当路由发生变化的时候,就把最新的地址给到pagepath变量

       作用是为了保持路由菜单栏的高亮显示,以及解决点击不跳转的bug */

    $route: {

      handler: function (newV) {

        console.log(newV);

        this.pagepath = newV.path;

      },

      immediate: true,

    },

  },

  created: function () {

    this.getNaviList();

  },

  methods: {

    getNaviList: function () {

      axios

        .get("/mork/menu.json", {

          headers: {

            Authorization: localStorage.token,

          },

        })

        .then((res) => {

          console.log(res);

          let { data, meta } = res.data;

          /* 数据获取成功 */

          if (meta.status == 200) {

            this.navList = data;

            /* 动态添加路由 */

            /* 因为第一个路由是默认的所以我们从第二个路由开始动态添加 */

            console.log(this.navList);

            let arr = this.navList.slice(1,3)

            /* 循环路由数组 动态添加路由 */

            console.log(arr);

            arr.forEach(v => {

              /* 我们尽量使用v.children[0].path 原因是我们的路径名用的是子路由的 */

             /* 如果我们直接写死 v.children[0].path 会导致只有一个子路由的路径被动态添加了

                如果有多个就无法生效, 所以我们要二次循环v.children,从而实现多个二级子路由

                能够被动态的添加*/

             v.children.forEach(r=>{

                this.$router.addRoute("index",

              {

                path:r.path,

                name:r.path,

                component:()=>import(`@/views/${r.path.substring(0,1).toUpperCase()+r.

                path.substring(1)}View.vue`),

              },

              );

              })

              this.$router.addRoute("index",

              {

                path:v.children[0].path,

                name:v.children[0].path,

                component:()=>import(`@/views/${v.children[0].path.substring(0,1).toUpperCase()+v.children[0].

                path.substring(1)}View.vue`),

              },

              );

            });

            console.log(this.$router);

          } else {

            /* 防止数据获取失败给出相应的后台提示 */

            this.$message.error(meta.msg);

          }

        })

        .catch((err) => {

          console.log(err);

        });

    },

  },

};

</script>

<style scoped>

.el-header {

  background-color: #b3c0d1;

  color: #333;

  line-height: 60px;

}

.el-aside {

  color: #333;

}

</style>

router下路由配置:采取动态路由,之前的注释掉了:

import Vue from 'vue'

import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [

  {

    path: '/',

    name: 'login',

    component:()=>import('@/views/LoginView.vue')

  },

  {

    path:'/index',

    name:'index',

    /* 已进入页面就默认进入二级路由users页面 */

    redirect:'/index/users',

    component:()=>import('@/views/IndexView.vue'),

     children:[{

      path:'users',

      name:'users',

      component:()=>import('../views/UsersView.vue'),

      },

      {

        path:'addusers',

      name:'addusers',

      component:()=>import('../views/AddusersView.vue'),

      }

     /* {

       path:'roles',

       name:'roles',

       component:()=>import('../views/RolesView.vue'),

     },

     {

       path:'rights',

       name:'rights',

       component:()=>import('../views/RightsView.vue'),

     },

     {

       path:'goods',

       name:'goods',

       component:()=>import('../views/GoodsView.vue'),

     },

     {

       path:'params',

       name:'params',

       component:()=>import('../views/ParamsView.vue'),

     },

     {

       path:'categories',

       name:'categories',

       component:()=>import('../views/CategoriesView.vue'),

     },

     {

       path:'categories',

       name:'categories',

       component:()=>import('../views/CategoriesView.vue'),

     },

     {

       path:'orders',

       name:'ordes',

       component:()=>import('../views/OrdersView.vue'),

     },

     {

       path:'reports',

       name:'reports',

       component:()=>import('../views/ReportsView.vue'),

     }, */

  ]

  }

]

const router = new VueRouter({

  routes

})

export default router

views下跳转的AddcategoriesView.vue:

<template>

  <div><h1>添加分类</h1></div>

</template>

<script>

export default {

}

</script>

<style>

</style>

效果图:


代码目录:


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容