2021.12.10 vue 路由 (13)

什么是路由?

这里的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(single page application)的路径管理器。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。

传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。

至于我们为啥不能用a标签,这是因为用Vue做的都是单页应用(当你的项目准备打包时,运行npm run build时,就会生成dist文件夹,这里面只有静态资源和一个index.html页面),所以你写的标签是不起作用的,你必须使用vue-router来进行管理。

vue-router的实现原理之hash模式

单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;

vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式。

hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。

vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说hash 出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面;

<div class='main'>
  <a href="#md1">锚点1</a>
  <a href="#md2">锚点2</a>
</div>
<div id="md1"></div>
  <hr>
<div id="md2"></div>

以上代码解释了html页面中锚点的作用,即,当点击锚点2的a标签时,页面回跳至id为md2的div位置

路由简易实现

<body>
  <div id='app'>
    <!-- router-link 会被默认渲染成a标签,to属性会被渲染成href属性 -->
    <router-link to='/liub'>刘邦</router-link>
    <router-link to='/liuh'>刘恒</router-link>
    <router-link to='/liuq'>刘启</router-link>
    <router-view></router-view>
  </div>

  <script src='./js/vue.js'></script>
  <script src='./js/vue-router_3.0.2.js'></script>
  <script>
    // 1. 定义(路由)组件.
    // 因为是组件,所以当使用单文件组件时,可以从其他文件import进来
    const lb = {
      template: '<h3>汉高祖</h3>'
    }
    const lh = {
      template: '<h3>汉文帝</h3>'
    }
    const lq = {
      template: '<h3>汉景帝</h3>'
    }

    // 2.创建router实例,然后传入routes配置
    const router = new VueRouter({
      // 3. 定义路由
      // 每个路由应该映射一个组件,其中'component'可以是通过extend创建的组件构造器
      routes: [
        { path: '/liub', component: lb },
        { path: '/liuh', component: lh },
        { path: '/liuq', component: lq }
      ]
    })
    const app = new Vue({
      el: '#app',
      // 4.挂载到根实例
      router,
      data: {

      }
    })
  </script>
</body>

router-link的标签自定义

  <div id='app'>
    <router-link to='/liub' tag='button'>刘邦</router-link>
    <router-link to='/liuh'>刘恒</router-link>
    <router-link to='/liuq'>刘启</router-link>
    <router-view></router-view>
  </div>

router-link默认渲染成a标签, tag属性, 可以指定渲染后的目标标签

const router = new VueRouter({
  routes: [
    { path: '/liub', component: lb },
    { path: '/liuh', component: lh },
    { path: '/liuq', component: lq }
  ],
  linkActiveClass: 'abc',
  linkExactActiveClass: 'cde'
})

上述俩属性, 可以自定义被激活路由元素的class名称

路由重定向

routes: [
  { path: '/', redirect: '/liub' },
  { path: '/liub', component: lb },
  { path: '/liuh', component: lh },
  { path: '/liuq', component: lq }
],

当访问到根路径时自动跳转到/liub,注意是跳转,并不是默认显示/liub

routes: [
  // redirect重定向
  // { path: '/', component: lb },
  // 写法1
  // { path: '/', redirect: '/liub' },
  // 写法2
  // { path: '/', redirect: { path: '/liub' } },
  { path: '/', redirect: { name: 'lb' } },
  // 写法3
  // 方法接收 目标路由最为参数
  // return 返回重定向的字符串
  // { path: '/', redirect: to => { return '/liub' } },
  { path: '/liub', component: lb },
  { path: '/liuh', name: 'lb', component: lh },
  { path: '/liuq', component: lq }
],

路由重命名

“重定向”的意思是,当用户访问/时,URL 将会被替换成/liub,然后匹配路由为/liub,那么“别名”又是什么呢?

/demo 的别名是 /liub,意味着,当用户访问demo 时,URL 会保持为 /liub,但是路由匹配则为/demo,就像用户访问/demo 一样。

上面对应的路由配置为:

routes: [
  { path: '/demo', component: demo, alias: '/liub' },
  { path: '/liub', component: lb },
  { path: '/liuh', component: lh },
  { path: '/liuq', component: lq }
]

“别名”的功能让你可以自由地将UI 结构映射到任意的URL,而不是受限于配置的嵌套路由结构。

路由嵌套

当我们的一个组件里有子组件时,这个时候我们就需要使用嵌套路由访问到组件的子组件里面的内容

<body>
  <div id='app'>
    <router-link to='/liub' tag='button'>刘邦</router-link>
    <router-link to='/liuh'>刘恒</router-link>
    <router-link to='/liuq'>刘启</router-link>
    <router-view></router-view>
  </div>

  <template id="lb">
    <div>
      <h3>汉高祖</h3>
      <!-- 子路由连接 -->
      <router-link to='/liub/liuy'>嫡长子刘盈</router-link>
      <router-link to='/liub/liuf'>长子刘肥</router-link>
      <!-- 子路由占位符 -->
      <router-view></router-view>
    </div>
  </template>

  <script src='./js/vue.js'></script>
  <script src="./js/vue-router_3.0.2.js"></script>
  <script>
    const lb = {
      template: '#lb'
    }
    const lh = {
      template: '<h3>汉文帝</h3>'
    }
    const lq = {
      template: '<h3>汉景帝</h3>'
    }

    const ly = {
      template: '<h3>我是刘邦的嫡长子刘盈</h3>'
    }
    const lf = {
      template: '<h3>我是刘邦的长子刘肥</h3>'
    }

    const router = new VueRouter({
      routes: [
        {
          path: '/liub',
          component: lb,
          children: [
            { path: '/liub/liuy', component: ly },
            { path: '/liub/liuf', component: lf }
          ]
        },
        { path: '/liuh', component: lh },
        { path: '/liuq', component: lq }
      ],
      linkActiveClass: 'abc',
    })


    const app = new Vue({
      el: '#app',
      router,
      data: {
      }
    })
  </script>
</body>

动态路由匹配

<body>
  <div id='app'>
    <router-link to='/liub' tag='button'>刘邦</router-link>
    <router-link to='/liuh/1'>刘恒1</router-link>
    <router-link to='/liuh/2'>刘恒2</router-link>
    <router-link to='/liuq'>刘启</router-link>
    <router-view></router-view>
  </div>

  <template id="lb">
    <div>
      <h1>汉高祖</h1>
      <!-- 子路由连接 -->
      <router-link to='/liub/liuy'>嫡长子刘盈</router-link>
      <router-link to='/liub/liuf'>长子刘肥</router-link>
      <!-- 子路由占位符 -->
      <router-view></router-view>
    </div>
  </template>

  <script src='./js/vue.js'></script>
  <script src='./js/vue-router_3.0.2.js'></script>
  <script>
    const lb = {
      template: '#lb'
    }
    const lh = {
      template: '<h3>我是刘恒的组件,我的id是:{{$route.params.id}}</h3>'
    }
    const lq = {
      template: '<h3>汉景帝</h3>'
    }
    const ly = {
      template: '<h3>我是刘邦嫡长子刘盈</h3>'
    }
    const lf = {
      template: '<h3>我是刘邦长子刘肥</h3>'
    }

    const router = new VueRouter({
      routes: [
        { path: '/', redirect: '/liub' },
        {
          path: '/liub',
          component: lb,
          children: [
            { path: '/liub/liuy', component: ly },
            { path: '/liub/liuf', component: lf }
          ]
        },
        { path: '/liuh/:id', component: lh },
        { path: '/liuq', component: lq }
      ],
      linkActiveClass: 'abc',
    })

    const app = new Vue({
      el: '#app',
      router,
      data: {
      }
    })
  </script>
</body>

路由props

<body>
  <div id='app'>
    <router-link to='/liub' tag='button'>刘邦</router-link>
    <router-link to='/liuh/1'>刘恒1</router-link>
    <router-link to='/liuh/2'>刘恒2</router-link>
    <!-- <router-link :to="{name:'liuq'}">刘启</router-link> -->
    <router-link :to="{name:'liuq', params:{id:5,name:'李四',age:500}}">刘启</router-link>
    <router-view></router-view>
  </div>

  <template id="lb">
    <div>
      <h1>汉高祖</h1>
      <!-- 子路由连接 -->
      <router-link to='/liub/liuy'>嫡长子刘盈</router-link>
      <router-link to='/liub/liuf'>长子刘肥</router-link>
      <!-- 子路由占位符 -->
      <router-view></router-view>
    </div>
  </template>

  <script src='./js/vue.js'></script>
  <script src='./js/vue-router_3.0.2.js'></script>
  <script>
    const lb = {
      template: '#lb'
    }
    const lh = {
      template: '<h3>我是刘恒的组件,我的id是:{{$route.params.id}}</h3>'
    }
    const lq = {
      props: ['name', 'age'],
      template: '<h3>汉景帝{{$route.params.id}}-->{{name}}-->{{age}}</h3>'
    }

    const ly = {
      template: '<h3>我是刘邦嫡长子刘盈</h3>'
    }
    const lf = {
      template: '<h3>我是刘邦长子刘肥</h3>'
    }

    const router = new VueRouter({
      routes: [
        { path: '/', redirect: '/liub' },
        {
          path: '/liub',
          component: lb,
          children: [
            { path: '/liub/liuy', component: ly },
            { path: '/liub/liuf', component: lf }
          ]
        },
        { path: '/liuh/:id', component: lh },
        // { path: '/liuq/:id', name: 'liuq', component: lq, props: route => (console.log(route), { name: '张三', age: 20 }) }
        { path: '/liuq/:id', name: 'liuq', component: lq, props: route => (console.log(route), { name: route.params.name, age: route.params.age }) }
      ],
      linkActiveClass: 'abc',
    })

    const app = new Vue({
      el: '#app',
      router,
      data: {
      }
    })
  </script>
</body>

编程式导航

上述都是使用一个声明出来的固定元素来实现跳转, 但这种方法局限性大, 必须要有某个固定的触发元素, 为了实现更加柔性的跳转, 我们就引申出编程式的导航

业务场景:在一个路由组件里面点击可以切换到另一个路由组件

this.$router.push(“目标路径”)// 强制跳转至某一路径

this.$router.go(-1)//返回上一级

this.$router.replace(“目标路径”)//路由替换

methods: {
  go_lh() {
    // push 直接跳转到某个组件页面
    // console.log(this.$router.push('/liuh/1'));
    this.$router.replace('/liuh/2')
  }
}
......
methods: {
  go_back() {
    // 回退
    this.$router.go(-1)
  }
}

路由案例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<style type="text/css">
  html,
  body,
  #app {
    margin: 0;
    padding: 0px;
    height: 100%;
  }

  .header {
    height: 50px;
    background-color: #131A20;
    line-height: 50px;
    text-align: center;
    font-size: 24px;
    color: #fff;
  }

  .footer {
    height: 40px;
    line-height: 40px;
    background-color: #888;
    position: absolute;
    bottom: 0;
    width: 100%;
    text-align: center;
    color: #fff;
  }

  .main {
    display: flex;
    position: absolute;
    top: 50px;
    bottom: 40px;
    width: 100%;
  }

  .content {
    flex: 1;
    text-align: center;
    height: 100%;
  }

  .left {
    flex: 0 0 20%;
    background-color: #1E1E1E;
  }

  .left a {
    color: white;
    text-decoration: none;
  }

  .right {
    margin: 5px;
  }

  .btns {
    width: 100%;
    height: 35px;
    line-height: 35px;
    background-color: #f5f5f5;
    text-align: left;
    padding-left: 10px;
    box-sizing: border-box;
  }

  button {
    height: 30px;
    background-color: #ecf5ff;
    border: 1px solid lightskyblue;
    font-size: 12px;
    padding: 0 20px;
  }

  .main-content {
    margin-top: 10px;
  }

  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  ul li {
    height: 45px;
    line-height: 45px;
    background-color: #545555;
    color: #fff;
    cursor: pointer;
    border-bottom: 1px solid #fff;
  }

  table {
    width: 100%;
    border-collapse: collapse;
  }

  td,
  th {
    border: 1px solid #eee;
    line-height: 35px;
    font-size: 12px;
  }

  th {
    background-color: #ddd;
  }
</style>
<body>
  <div id='app'>
    <!-- 占位放app -->
    <router-view></router-view>
  </div>
  <!-- 页面主组件 -->
  <template id="web">
    <div>
      <!-- 头部区域 -->
      <header class="header">享学后台管理系统</header>
      <!-- 中间主体区域 -->
      <div class="main">
        <!-- 左侧菜单栏 -->
        <div class="content left">
          <ul>
            <li>
              <router-link to="/user">用户管理</router-link>
            </li>
            <li>
              <router-link to="/rights">权限管理</router-link>
            </li>
            <li>
              <router-link to="/goods">商品管理</router-link>
            </li>
            <li>
              <router-link to="/orders">订单管理</router-link>
            </li>
            <li>
              <router-link to="/settings">系统设置</router-link>
            </li>
          </ul>
        </div>
        <!-- 右侧内容区域 -->
        <div class="content right">
          <div class="main-content">
            <router-view></router-view>
          </div>
        </div>
      </div>
      <!-- 尾部区域 -->
      <footer class="footer">版权信息</footer>
    </div>
  </template>

  <!-- user组件 -->
  <template id="user">
    <div>
      <table>
        <thead>
          <tr>
            <th>编号</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>操作1</th>
            <th>操作2</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for='(item,index) in userlist' :key='item.id'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.age}}</td>
            <td>
              <button @click='detail(item.id, item.det)'>详情</button>
            </td>
            <td>
              <button @click='del(index)'>删除</button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </template>
  <script src=' ./js/vue.js'></script>
  <script src='./js/vue-router_3.0.2.js'></script>
  <script>
    const app = {
      template: '#web'
    }
    const user = {
      template: '#user',
      data() {
        return {
          userlist: [
            { id: 1, name: '张三', age: 10, det: '我是张三我很帅' },
            { id: 2, name: '李四', age: 10, det: '我是李四我贼帅' },
            { id: 3, name: '王五', age: 10, det: '我是王五我无敌帅' },
          ]
        }
      },
      methods: {
        detail(id, det) {
          this.$router.push(`/user_info/${id}${det}`)
        },
        del(index) {
          this.userlist.splice(index, 1)
        }
      }
    }
    const rights = {
      template: '<div><h3>权限管理区域</h3></div>'
    }
    const goods = {
      template: '<div><h3>商品管理区域</h3></div>'
    }
    const orders = {
      template: '<div><h3>订单管理区域</h3></div>'
    }
    const settings = {
      template: '<div><h3>系统设置区域</h3></div>'
    }
    const user_info = {
      props: ['id'],
      template: '<div><h2>用户详情</h2><h3>用户信息:{{id}}</h3><button @click="go_back">回退</button></div>',
      methods: {
        go_back() {
          this.$router.go(-1)
        }
      }
    }

    const router = new VueRouter({
      routes: [
        {
          path: '/', redirect: '/user', component: app, children: [
            { path: '/user', component: user },
            { path: '/rights', component: rights },
            { path: '/goods', component: goods },
            { path: '/orders', component: orders },
            { path: '/settings', component: settings },
            { path: '/user_info/:id', component: user_info, props: true },
          ]
        },

      ]
    })
    const vm = new Vue({
      el: '#app',
      router,
      data: {

      }
    })
  </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值