前端与移动开发----Vue---- 路由

路由-前端路由

路由的概念其实是从后端来的。

  • 根据某个访问的路径,进行逻辑处理,并返回 ------ 接口

前端的路由:一个路径,对应某个页面。

问题导入

在前面完成的资产管理案例中, 我们是把列表区域添加表单区域实现在了一个页面中。当页面功能比较复杂时,我们需要它们拆分开来:一个页面中只显示一个区域。

一个比较直观的解决方案是把它们分别做成两个独立的网页文件,例如:

文件一: xxxx/index.html 显示表格区区域

文件二:xxxx/add.html显示表单区域

然后添加一个导航条来允许用户进行跳转。

这种解决方案比较直接了当,但它存在一些问题:

  • 从一个页面跳入另一个页面需要重新加载公共的资源文件,造成浪费。例如index.html中需要用到axios.js,在add.html中也需要用到。
  • 页面的跳入跳出给用户的体验也不好(特别地,是在移动端)。

那有没有一种方案在不进行页面跳转(不刷新整个页面,只存在一个.html页面)的前提下,能根据地址栏中的地址不同,来显示不同的内容?

有,这就是前端路由技术。
前端路由

  • 根据地址栏变化(不发请求),去局部更新不同的页面内容。
    • 前端业务场景切换。

路由-实现原理

地址栏中的#有两个含义:

  • 锚点链接: 在当前网页内部进行跳转。示例:https://baike.baidu.com/item/%E9%94%9A%E7%82%B9#3

  • 哈希值(hash): 它的作用是,当它发生变化时,它不会导致当前页面的刷新值,但是它的变化会触发hashchange事件,这个事件能被监听到

路由原理

​ 当hash变化时,更新内容,以达成显示不同内容的目标。

  • hashchange: 在window上添加这个事件监听
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div>
    <a href="#/index">主页</a>
    <a href="#/add">添加</a>
    <a href="#/sql">搜索</a>
  </div>

  <div id="container">
    <!-- 容器,根据自己约定的路由规则来显示不同的内容 -->
  </div>
  <script>
    // 这里的index, add就是我们自己约定的路由规则:
    // index ----> 主页
    // add   ----> 添加
    // seq   ----> 搜索

    function hashChangeCallback () {
     
     
      if(window.location.hash === '#/index') {
     
     
        // 应该要显示主页
        document.getElementById('container').innerHTML = `
          我是一个主页,我这里有一个表格
        `
      } else if (window.location.hash === '#/add') {
     
     
        // 应该要显示添加
        document.getElementById('container').innerHTML = `
          我是一个添加页,我这里有一个表单
        `
      } else if (window.location.hash === '#/sql') {
     
     
        // 应该要显示添加
        document.getElementById('container').innerHTML = `
          搜索
        `
      }
    }

    window.addEventListener('DOMContentLoaded', () => {
     
     
      // 页面加载完成
      console.log('DOMContentLoaded')
      hashChangeCallback()
    })

    window.addEventListener('hashchange', () => {
     
     
      // 哈希值变化了
      console.log('哈希值变化了', window.location)
      hashChangeCallback()
    })
  </script>

</body>
</html>

技术要点:

  • 地址url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,比如典型的回到顶部按钮原理、Github 上各个标题之间的跳转等,路由里的 # 不叫锚点,我们称之为 hash。地址栏中hash的变化是不会发生页面跳转的。
  • hashchange 事件用来监听hash值的变化。
  • hash的改变也会记录到浏览历史中,通过回退和前进可以切换业务场景

SPA

单页面应用程序,简称SPA(single page application)一个系统上的所有功能在一个页面上实现,

(在移动端比较多,只要是用Vue开发的应用,绝大多数都是SPA)

SPA是通过前端路由实现业务场景的切换的。

在vue框架中额外引入vue-router插件来配合组件系统就可以轻易地实现。

在前端的三大框架中,都有成型的SPA的解决方案。

在单页面应用程序中,如何切换页面的业务场景。

优点:

  • 整体不刷新页面,用户体验更好。

缺点:

  • 首次加载会比较慢一点,后面也会讲优化的方式。

使用vue-router

vue-router是vue的一个插件,当我们的项目需要前端路由时,我们要先把它下载引入到页面中。

下载: https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js

导入插件

与vue的使用方法一样:

# 先下载到本地,再引用
<script src="./vue-router.min.js"></script>
# 直接引用
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>

要先引入vue,后引入vue-router

初始化vue-router插件

用VueRouter构造器创建路由实例,并配置路由规则。

基本格式

const router = new VueRouter({
    
    
	routes: [
        {
    
    path:"路径1",component:要展示的组件1},
        {
    
    path:"路径2",component:要展示的组件2},
        .....
    ]
})
  • path, component, routes 都是固定写法。

示例

  • vue-router中有一套约定的规则用来确定在哪个url下显示哪个组件。
// 初始化vue-router且使用刚定义的路由规则
const router = new VueRouter({
    
    
    // 初始化路由的配置对象
    // 有以一个配置项 routes 定义路由规则
    routes:[
        {
    
    path: '/', component: {
    
    template:`<div>我是主页</div>`}},
        {
    
    path: '/news', component: {
    
    template:`<div>新闻-生活早知道</div>`}},
        {
    
    path: '/sport', component: {
    
    template:`<div>体育-体育改变人生</div>`} 			}
    ]
})

使用路由实例

在 Vue构造器中,有一项是router,它专门用来设置路由对象

new Vue({
    
    
    el: '#app',
    // vue提供了一个配置选项,router选项,是用来挂载路由实例的
    // 只有挂载了 router 实例 才可使用路由的功能
    router:路由对象
})

设置路由出口

在vue的模板,添加一个router-view组件,用它来指定当前路由对应组件渲染的位置。

<!-- 渲染路由对应的组件 router-view承载路由对应的组件的-->
<router-view></router-view>

测试使用

请直接在地址栏中补充对应的路由地址来查看路由效果。

http://127.0.0.1:5500/xxxxx.html#/news

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <style>
        body{
     
     
            background-color: #ccc;
        }
        #app{
     
     
            width: 400px;
            margin: 20px auto;
            background-color: #fff;
            border:4px solid blueviolet;
            border-radius: 1em;
            box-shadow: 3px 3px 3px rgba(0, 0, 0, .5);
            padding:1em 2em 2em;
        }
        h3{
     
     
            text-align: center;
        }
        .title{
     
     
            display: flex;
            justify-content: space-between;
            align-items: center;
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .title h4{
     
     line-height: 2;margin:0;}
        .container{
     
     
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .btn {
     
     
            /* 鼠标改成手的形状 */
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div id="app">
      <nav>
        <ul>
          <li><a href="#/index">主页</a></li>
          <li><a href="#/add">添加</a></li>
          <li><a href="#/seq">查询</a></li>
        </ul>
      </nav>
      <!-- 路由出口
        router-view是vue-router.js中提供的全局组件
        用来装入 根据路由规则匹配成功的组件
      -->
      <router-view></router-view>
    </div>
    <script>

      const seq = {
     
      name: 'seq', template: '<div>我是搜索页</div>' }
      // 1. 初始化vue-router: 用vueRouter去new一个路由对象
      //   VueRouter是在vue-router.js中提供的一个构造器
      const router = new VueRouter({
     
     
        // routes: 配置路由规则
        routes: [
          // { path: 路由地址1, component: 当地址栏访问路由地址1时,要显示的组件 }
          // path, component都是固定写法
          {
     
      path: '/index', component: {
     
      name: 'index', template: '<div>我是spa的主页,有什么可以帮助你的吗?</div>' } },
          {
     
      path: '/add', component: {
     
      name: 'add', template: '<div>我是spa的添加页,要加个钟吗?</div>' } },
          {
     
      path: '/seq', component: seq },
        ]
      })

      // 2. 在vue实例中,使用router配置项,配置当前要使用的路由对象
      const vm = new Vue({
     
     
        el: "#app",
        // router是一个配置项,固定写法。就和el, data, methods一样。
        router: router
      })

      // 3. 在模板中设置路由出口 --- 添加一个容器,来用装入对应的组件
    </script>
</body>
</html>

路由链接导航

通过router-link来进行路由跳转。

<!-- 写路由链接 不会使用a标签  使用router-link组件 -->
<nav>
    <!-- 组件默认解析的是a标签  to属性跳转的地址,不需要带上# -->
    <li>
            <!-- router-link: vue-router提供的全局组件,有一个to属性,来进行跳转 -->
            <router-link to="/index">主页</router-link>
          </li>
          <li>
            <router-link to="/add">添加</router-link>
          </li>
          <li>
            <router-link to="/seq">查询</router-link>
          </li>
</nav>
  • router-link组件会被vue解析成a标签,但不能直接通过a标签来跳转。
  • 如果当前路由被激活会添加特殊的类名:
router-link-exact-active router-link-active

动态路由

目标:实现新闻详情的功能:即不同的新闻页使用同一个组件,根据传入的参数不同,达到显示不同内容的目标。

场景: 当你遇到详情页,就可以使用动态路由。

概念:不同的路由地址,指向同一个组件,此时需要使用动态路由。

示图:

在这里插入图片描述

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        body{
     
     
            background-color: #ccc;
        }
        #app{
     
     
            width: 400px;
            margin: 20px auto;
            background-color: #fff;
            border:4px solid blueviolet;
            border-radius: 1em;
            box-shadow: 3px 3px 3px rgba(0, 0, 0, .5);
            padding:1em 2em 2em;
        }
        h3{
     
     
            text-align: center;
        }
        .title{
     
     
            display: flex;
            justify-content: space-between;
            align-items: center;
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .title h4{
     
     line-height: 2;margin:0;}
        .container{
     
     
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .btn {
     
     
            /* 鼠标改成手的形状 */
            cursor: pointer;
        }
        .router-link-active {
     
     
          color: red;
          font-size:30px;
        }
    </style>
</head>
<body>
    <div id="app">
      <nav>
        <ul>
          <li>
            <!-- router-link: vue-router提供的全局组件,有一个to属性,来进行跳转 -->
            <router-link to="/index">主页</router-link>
          </li>
          <li>
            <router-link to="/add">添加</router-link>
          </li>
          <li>
            <router-link to="/seq/18">查看18号</router-link>
            <router-link to="/seq/28">查看28号</router-link>
          </li>
           
        </ul>
      </nav>
      <!-- 路由出口
        router-view是vue-router.js中提供的全局组件
        用来装入 根据路由规则匹配成功的组件
      -->
      <router-view></router-view>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <script>


      // 1. 初始化vue-router: 用vueRouter去new一个路由对象
      //   VueRouter是在vue-router.js中提供的一个构造器
      const router = new VueRouter({
     
     
        // routes: 配置路由规则
        routes: [
          // { path: 路由地址1, component: 当地址栏访问路由地址1时,要显示的组件 }
          // path, component都是固定写法
          {
     
      path: '/index', component: {
     
      name: 'index', template: '<div>我是spa的主页,有什么可以帮助你的吗?</div>' } },
          {
     
      path: '/add', component: {
     
      name: 'add', template: '<div>我是spa的添加页,要加个钟吗?</div>' } },

          // path: '/seq/:id':它会匹配所有 /seq/12 或者是 /seq/18  .... 这类地址
          //                   同时,12(18)会传给这里的id。理解:id是一个占位符。

          // $route: 理解为一个全局变量:它在所有的组件中都可以直接访问。它其实是一个对象 ,是vueRouter.js添加到组件上的
          //         一个对象,它里面保存着当前路由信息. $route.params中保存着动态路由传递的参数
          {
     
      path: '/seq/:id', component: {
     
      name: 'seq', template: '<div>我是查询页 {
     
     {$route.params.id}}</div>' } }
        ]
      })

      // 2. 在vue实例中,使用router配置项,配置当前要使用的路由对象
      const vm = new Vue({
     
     
        el: "#app",
        // router是一个配置项,固定写法。就和el, data, methods一样。
        router: router
      })

      // 3. 在模板中设置路由出口 --- 添加一个容器,来用装入对应的组件
    </script>
</body>
</html>

总结:

  • 在路由规则中,匹配到不同的地址,指向同一个组件
  • 代码:
    • 定义路由时,注意::id。 {path:'/seq/:id', component: seq}
  • 数据:模板 { {$route.params.id}} 组件 this.$route.params.id

编程式导航

页面跳转(路由地址切换)有两种方式:

  1. 声明式导航。通过用户点击链接。router-link, to, 或者是 a href=’’。

    它比较适合于固定不变化的导航栏。

  2. 编程式导航。通过this.$router.push(地址)跳转。

    它比较适合于需要根据业务逻辑跳入不同页面的情况,例如,登陆功能。

格式

this.$router.push(地址)
$router: 是组件上的一个对象,在它的原型对象上面有很多的方法, push()用来做路由切换。

this.$router.push('/index')

应用场景:需要根据逻辑判断,跳入不同的页面,就可以使用编程式导航。例如:登陆功能。

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        body{
     
     
            background-color: #ccc;
        }
        #app{
     
     
            width: 400px;
            margin: 20px auto;
            background-color: #fff;
            border:4px solid blueviolet;
            border-radius: 1em;
            box-shadow: 3px 3px 3px rgba(0, 0, 0, .5);
            padding:1em 2em 2em;
        }
        h3{
     
     
            text-align: center;
        }
        .title{
     
     
            display: flex;
            justify-content: space-between;
            align-items: center;
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .title h4{
     
     line-height: 2;margin:0;}
        .container{
     
     
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .btn {
     
     
            /* 鼠标改成手的形状 */
            cursor: pointer;
        }
        .router-link-active {
     
     
          color: red;
          font-size:30px;
        }
    </style>
</head>
<body>
    <div id="app">
      <!-- 在模块写路由出口 -->
      <router-view></router-view>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <script>

      const router = new VueRouter({
     
     
        routes: [
          // 路由规则
          {
     
      
            path: '/login', 
            component: {
     
      
              name: 'login', 
              template: `
                  <div>登陆页
                    <button @click="hLogin">点击登陆</button>
                  </div>
              `,
              methods: {
     
     
                hLogin () {
     
     
                  console.log(this.$router)
                  // 假设有50%的可能性
                  if (Math.random() > 0.5) {
     
     
                    // 跳入login.vue
                    // this.$router.push(地址)
                    // $router: 是组件上的一个对象,在它的原型对象上面有很多的方法, push()用来做路由切换。
                    this.$router.push('/index')
                  } else {
     
     
                    alert('失败')
                  }
                }
              }
            }
          },
          {
     
      path: '/index', component: {
     
      name: 'index', template: `<div>我是主页</div>`}}
        ]
      })
      const vm = new Vue({
     
     
        el: "#app",
        router: router

      })
    </script>
</body>
</html>

路由-页面跳转及传参

目标

从页面(路由)pageA跳转到pageB(路由) ,并携带参数,在pageB中接收这个参数

跳转有两种方式

  • 声明式:通过router-link的to属性跳转
  • 编程式:通过$router.push()方法来跳转

传参有两种方式

  • 查询传参 /pageB?id=1001
  • 路径传参 /pageB/1001

获取传参数的方式: (根据传参不同,获取参数也不同)

-  查询传参: this.$route.query.id
-  路径传参: this.$route.params.id

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        body{
     
     
            background-color: #ccc;
        }
        #app{
     
     
            width: 400px;
            margin: 20px auto;
            background-color: #fff;
            border:4px solid blueviolet;
            border-radius: 1em;
            box-shadow: 3px 3px 3px rgba(0, 0, 0, .5);
            padding:1em 2em 2em;
        }
        h3{
     
     
            text-align: center;
        }
        .title{
     
     
            display: flex;
            justify-content: space-between;
            align-items: center;
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .title h4{
     
     line-height: 2;margin:0;}
        .container{
     
     
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .btn {
     
     
            /* 鼠标改成手的形状 */
            cursor: pointer;
        }
        .router-link-active {
     
     
          color: red;
          font-size:30px;
        }
    </style>
</head>
<body>
    <div id="app">
      <h2>目标:从pageA跳到pageB并带参数</h2>
      <nav>
        <ul>
          <li>
            <hr>
            <h3>查询传参 - pageB?id=1&age=3</h3>
            <!-- 1. 声明式跳转 并传参-查询传参-->
            <router-link to="/pageB?id=1&age=3">声明式跳转并传参-查询传参</router-link>
            <button @click="$router.push('/pageB?id=1&age=3')">编程式跳转并传参-查询传参</button>
          </li>

          <li>
            <hr>
            <h3>路径传参 - 动态路由pageA/1/3</h3>
            <!-- 1. 声明式跳转 并传参-查询传参-->
            <router-link to="/pageA/1/3">声明式跳转并传参-路径传参</router-link>
            <button @click="$router.push('/pageA/1/3')">编程式跳转并传参-路径传参</button>
          </li>
          
        </ul>
      </nav>
      
      <!-- 路由出口
        router-view是vue-router.js中提供的全局组件
        用来装入 根据路由规则匹配成功的组件
      -->
      <router-view></router-view>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <script>

      const seq = {
     
      name: 'seq', template: '<div>我是搜索页</div>' }
      // 1. 初始化vue-router: 用vueRouter去new一个路由对象
      //   VueRouter是在vue-router.js中提供的一个构造器
      const router = new VueRouter({
     
     
        // routes: 配置路由规则
        routes: [
          {
     
      
            path: '/pageB', 
            component:{
     
      
              template: `
                <div>
                  pageB, $route.query是一个对象, 用来接收通过查询传参的方式 传递的数据
                  pageB 从查询传参,{
      
      {$route.query.id}} - {
      
      {$route.query.age}}
                </div>` 
            }
          },
          {
     
      
            path: '/pageA/:id/:age', 
            component:{
     
      
              template: `
                <div>
                  pageA, $route.params是一个对象, 用来接收通过路径传参的方式 传递的数据
                  pageA 从查询传参,{
      
      {$route.params.id}} - {
      
      {$route.params.age}}
                </div>` 
            }
          }
        ]
      })

      // 2. 在vue实例中,使用router配置项,配置当前要使用的路由对象
      const vm = new Vue({
     
     
        el: "#app",
        // router是一个配置项,固定写法。就和el, data, methods一样。
        router: router
      })
    </script>
</body>
</html>

传参的不同,则获取参数的方式也不同。

pageA pageB
地址传参 <router-link to="/pageB?id=1&age=3" $route.query.id, $route.query.age
路径传参 <router-link to="/pageB/1/3" 。注意,在定义路由时,要把占位符提前写好:/pageB/:id/:age $route.params.id, $route.params.age

路由-页面跳转及传参-复杂对象

$router.push()实参有两种格式:

  • 字符串

    this.$router.push('/pageA?id=1&age=3')
    this.$router.push('/pageA/1/3')
    
  • 对象

    // 对于query方法的传参,内容一定会在地址栏中出现
    this.$router.push({
          
          
      path: '/pageB',
      query:{
          
          
        // query中的内容一定会在地址栏中出现
        arr: [1, 2, 3, 4, 6],
        id: 1,
        age: 100
      }
    })
    
    // 如果是路由传参,则必须要使用name属性
    this.$router.push({
          
          
      name: 'pageA', // 路由的名字
      params:{
          
          
        // 这个arr在页面跳转时,会传到目标页,但是它并不会出现
        // 地址栏中(因为在定义路由时,没有设置对应的占位符),
        arr: [1, 2, 3, 4, 6],
        id: 1,
        age: 100
      }
    })
    

结论: 如果要传递复杂的数据,则必须使用$router.push({name, params: {}})这种格式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        body{
     
     
            background-color: #ccc;
        }
        #app{
     
     
            width: 400px;
            margin: 20px auto;
            background-color: #fff;
            border:4px solid blueviolet;
            border-radius: 1em;
            box-shadow: 3px 3px 3px rgba(0, 0, 0, .5);
            padding:1em 2em 2em;
        }
        h3{
     
     
            text-align: center;
        }
        .title{
     
     
            display: flex;
            justify-content: space-between;
            align-items: center;
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .title h4{
     
     line-height: 2;margin:0;}
        .container{
     
     
            border:1px solid #ccc;
            padding: 0 1em;
        }
        .btn {
     
     
            /* 鼠标改成手的形状 */
            cursor: pointer;
        }
        .router-link-active {
     
     
          color: red;
          font-size:30px;
        }
    </style>
</head>
<body>
    <div id="app">
      <h2>目标:从pageA跳到pageB并带参数</h2>
      
           
      <button @click="hJumpQuery">编程式跳转并传参-查询传参</button>
      <button @click="hJumpParams">编程式跳转并传参-路径传参</button>
          
    
      <router-view></router-view>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
    <script>

      const seq = {
     
      name: 'seq', template: '<div>我是搜索页</div>' }
      // 1. 初始化vue-router: 用vueRouter去new一个路由对象
      //   VueRouter是在vue-router.js中提供的一个构造器
      const router = new VueRouter({
     
     
        // routes: 配置路由规则
        routes: [
          {
     
      
            path: '/pageB', 
            component:{
     
      
              template: `
                <div>
                  pageB, $route.query是一个对象, 用来接收通过查询传参的方式 传递的数据
                  pageB 从查询传参,{
      
      {$route.query.id}} - {
      
      {$route.query.age}}
                </div>` 
            }
          },
          {
     
      
            name: 'pageA',
            path: '/pageA/:id/:age', 
            // path: '/pageA', 
            component:{
     
      
              template: `
                <div>
                  pageA, $route.params是一个对象, 用来接收通过路径传参的方式 传递的数据
                  pageA 从查询传参,{
      
      {$route.params.id}} - {
      
      {$route.params.age}}
                </div>` 
            }
          }
        ]
      })

      // 2. 在vue实例中,使用router配置项,配置当前要使用的路由对象
      const vm = new Vue({
     
     
        el: "#app",
        // router是一个配置项,固定写法。就和el, data, methods一样。
        router: router,
        methods: {
     
     
          hJumpParams () {
     
     
            // $router.push() 中的实参可以是字符串,也可以是对象
            // this.$router.push('/pageA/1/100')
            // this.$router.push({
     
     
            //   name: '路由的名字',
            //   params: {
     
     
            //     // 要传递的数据
            //   }
            // })
            this.$router.push({
     
     
              name: 'pageA',
              params:{
     
     
                // 这个arr在页面跳转时,会传到目标页,但是它并不会出现
                // 地址栏中(因为在定义路由时,没有设置对应的占位符),
                arr: [1, 2, 3, 4, 6],
                id: 1,
                age: 100
              }
            })
          },
          hJumpQuery () {
     
     
            this.$router.push({
     
     
              path: '/pageB',
              query:{
     
     
                // query中的内容一定会在地址栏中出现
                arr: [1, 2, 3, 4, 6],
                id: 1,
                age: 100
              }
            })
          },
        }
      })
    </script>
</body>
</html>

路由重定向

重定向:

  • 当你访问某个地址的时候,经过程序的处理(用户看不见),跳转到了另外一个地址。

前端的路由,使用使用重定向功能,假设一个业务场景:

  • 当你访问页面的时候,默认hash地址是 #/ ,默认的路由地址 /
  • 此时我们项目的首页 /index,所以:当我们访问/重定向到/index,才能默认访问首页。

代码:

const router = new VueRouter({
    
    
        // routes: 配置路由规则
        routes: [
          // 重定向: 访问 A,给你跳到B
          // path: '/': 这个路径是页面打开时,默认的地址。可以让它重定向到主页
          {
    
     path: '/', redirect: '/index' },
          // { path: 路由地址1, component: 当地址栏访问路由地址1时,要显示的组件 }
          // path, component都是固定写法
          {
    
     path: '/index', component: {
    
     name: 'index', template: '<div>我是spa的主页,有什么可以帮助你的吗?</div>' } },
          {
    
     path: '/add', component: {
    
     name: 'add', template: '<div>我是spa的添加页,要加个钟吗?</div>' } },
          {
    
     path: '/seq', component: seq }
        ]
      })

总结:

  • 路由规则对象中 提供了一个选项:redirect 配置重定向的地址即可。

路由-404页

404页:当我们访问一个不存在的页面时,给出一个友好的提示:让用户访问404页

格式:

{ path: '*', component: { template: '<div>你要找的页面,被外星人吃掉了~~~</div>' } }

思路:其它的路由规则都没有匹配成功,用它来保底。

const router = new VueRouter({
    
    
        // routes: 配置路由规则
        routes: [
          // 重定向: 访问 A,给你跳到B
          // path: '/': 这个路径是页面打开时,默认的地址。可以让它重定向到主页
          {
    
     path: '/', redirect: '/index' },
          // { path: 路由地址1, component: 当地址栏访问路由地址1时,要显示的组件 }
          // path, component都是固定写法
          {
    
     path: '/index', component: {
    
     name: 'index', template: '<div>我是spa的主页,有什么可以帮助你的吗?</div>' } },
          {
    
     path: '/add', component: {
    
     name: 'add', template: '<div>我是spa的添加页,要加个钟吗?</div>' } },
          {
    
     path: '/seq', component: seq },
          // * 表示全部 , 实现404页
          // 上面的规则都没有匹配成功,就到这里来
          {
    
     path: '*', component: {
    
     template: '<div>你要找的页面,被外星人吃掉了~~~</div>' } }
        ]
      })

案例- 改写 资产管理的例子

改写 资产管理的例子,用vue-router来改写。

核心步骤:

1- 写一个基本的路由结构(引入路由,定义路由规则,在vue实例上挂载,设置路由出口)

2- 完成对应的组件

  • 添加功能,对应的组件
  • 主页,对应的组件

示例代码

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div id="app">
    <div class="container">
      <nav>
        <router-link to="/">主页</router-link>
        <router-link to="/add">添加</router-link>
      </nav>
      <!-- 路由容器 -->
      <router-view>

      </router-view>
    </div>
  </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 
<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>

  // 定义一个组件
  const pageAdd =  {
     
     
    template: `
      <div>
        <form class="form-inline">
          <input type="text" v-model.trim="asset.name" class="form-control" placeholder="资产名称">
          <input type="text" v-model.number="asset.price" class="form-control" placeholder="价格">
          &nbsp;&nbsp;&nbsp;&nbsp;
          <button class="btn btn-primary" @click.prevent="hAdd">添加资产</button>
        </form>
      </div>
    ` ,
    data () {
     
     
      return {
     
     
        asset: {
     
     
          name: '',
          price: ''
        }
      }
    },
    methods: {
     
     
      // 用户点击了添加按钮 
      hAdd () {
     
     
        console.log(this.asset)
        // 1. 解构赋值
        const {
     
      name, price } = this.asset
        
        // 2. if (用户的输入不合法,提示一下用户
        if (name === '') {
     
     
          alert('名字不能为空')
          return
        }

        if (price <= 0) {
     
     
          alert('价格不能是负数')
          return
        }
        // 3. 发请求
        axios({
     
     
          method: 'POST',
          url: 'http://localhost:3000/assets',
          data:{
     
     
            name: name,
            price: price
          }
        }).then(res => {
     
     
          console.log('添加成功')

          // 2. 清空表单数据
          this.asset.name = ''
          this.asset.price = ''

          // 3. 跳转到主页
          this.$router.push('/')
        })
      }
    }
  }
  
  const pageHome = {
     
     
    template: `
      <div>
        <!-- 搜索 -->
        <form class="form-inline" style="padding: 20px 0">
          <input type="text"
          v-model.trim="keyword"
          class="form-control" placeholder="输入关键字进行搜索">
        </form>
        <!-- 表格 -->
        <table class="table table-bordered table-hover">
          <thead>
            <tr>
              <th>编号</th>
              <th>资产名称</th>
              <th>价格</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            
            <tr v-for="(item, idx) in list">
              <td>{
      
      {idx}}</td>
              <td>{
      
      {item.name}}</td>
              <td>{
      
      {item.price}}</td>
              <td><a href="#" @click.prevent="hDelete(item.id)">删除</a></td>
            </tr>
            
            <tr v-if="list.length==0">
              <td colspan="4">没有数据</td>
            </tr>
          </tbody>
        </table>
      </div>`
    ,
    data () {
     
     
      return {
     
     
        list: [
          // {id:1,name:'商品1',price:1}
        ],
        keyword: '', // 用来做搜索的关键字
      }
    },
    created () {
     
     
      console.log('created....')
      this.loadData()
    },
    watch: {
     
     
      keyword: function(newVal, oldVal) {
     
     
        console.log(this.keyword)
        // 获取到用户要搜索的关键字
        // 如果关键字为空,就相当于是找全部的

        axios({
     
     
          method: 'GET',
          url: 'http://localhost:3000/assets',
          params: {
     
     
            name_like: this.keyword
          }
        }).then(res => {
     
     
          // 把查询到的数据更新到数据项中
          this.list = res.data
        })
      }
    },
    methods: {
     
     
      loadData () {
     
     
        // 1. 发ajax请求,获取全部的数据
        // 2. 把数据保存到data中的对应的数据项list中
        axios({
     
     
          method: 'GET',
          url: 'http://localhost:3000/assets'
        }).then(res => {
     
     
          console.log(res.data)
          // 数据变化了,视图也自动变化
          this.list = res.data
        })
      },
      hDelete (id) {
     
     

        if(!window.confirm('你确定要删除吗?')) {
     
     
          return
        }
        // alert(id)
        // 调用接口,发请求
        axios({
     
     
          method: 'DELETE',
          url: 'http://localhost:3000/assets/' + id
        }).then(res => {
     
     
          // 重新请求数据
          this.loadData()
        })
      }
    }
  }
  const router = new VueRouter({
     
     
    routes: [
      // 主页
      {
     
      path: '/', component: pageHome },
      {
     
      
        path: '/add', 
        component: pageAdd
      }
    ]
  })

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

</html>

路由嵌套

原理:router-view中再次包含router-view。

背景:一个组件内部包含的业务还是很复杂,需要再次进行拆分。

格式:

routes:[
    {
    
    
        path: '/sport', 
     	  component: {
    
    template:`<div><router-view></router-view></div>`},
        children: [
          {
    
     path:'/xx1', component: {
    
    }}
        ]
    }
]
  • 添加children

  • 在组件的模块中,再次添加router-view

示例

在这里插入图片描述

总结:

  • 在已有的路由容器中,再实现一套路由,再套一个路由容器,叫:嵌套路由。

代码:

<!DOCTYPE html>
<html lang="zh">
<head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>html页面</title>

 <style>
   body{
     
     
     background-color: #eee;
   }
   #app{
     
     
     background-color:#fff;
     width: 500px;
     margin: 50px auto;
     box-shadow: 3px 3px 3px rgba(0 , 0, 0, 0.5);padding:2em;
    }
   .box{
     
     
     padding: 1em;
     border:1px solid #ccc;
     margin:1em;
   }
   </style>
 </head>
 <body>
   <div id="app">
     <nav>
       <router-link to="/">主页</router-link>
       <router-link to="/news">新闻</router-link>
       <router-link to="/sports">体育</router-link>
     </nav>
     <router-view></router-view>
   </div>
   <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.js"></script>
   <script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js"></script>
   
   <script>
      const router = new VueRouter({
     
     
        routes: [
          {
     
      path: '/', component: {
     
      template: '<div>主页</div>'}},
          {
     
      path: '/news', component: {
     
      template: '<div>我是新闻页</div>'}},
          {
     
      
            path: '/sports',
            // 二级路由规则
            // 这里的设置的组件,如果路由匹配成功,它们会显示在当前component中的router-view中。
            children: [
              {
     
      path: '/sports/index', component: {
     
      name: 'sportsIndex', template: `<div>-体育栏目的主页</div>`}},
              {
     
      path: '/sports/guowai', component: {
     
      name: 'sportsGuowai', template: `<div>-国外体育新闻</div>`}},
              {
     
      path: '/sports/guonei', component: {
     
      name: 'sportsGuonei', template: `<div>国内体育新闻</div>`}}
            ],
            component: {
     
     
              template: `
              <div>
                <h3>体育-体育改变人生</h3>
                <nav>
                  <router-link to="/sports/index">主页</router-link>
                  <router-link to="/sports/guonei">国内</router-link>
                  <router-link to="/sports/guowai">国外</router-link>
                </nav>
                <router-view></router-view>
              </div>`
            }
          }
        ]
      })

      var vm = new Vue({
     
     
        el: '#app',
        router: router
      })
   </script>
 </body>
</html>

总结:

  • 嵌套路由除了 router-view 之间需要嵌套,路由规则也需要通过children来实现嵌套。

如有不足,请多指教,
未完待续,持续更新!
大家一起进步!

猜你喜欢

转载自blog.csdn.net/qq_40440961/article/details/112939742