427 单页面应用,vue路由

单页面应用程序

  • SPA : Single Page Application 单页面应用程序

  • MPA : Multiple Page Application 多页面应用程序

  • 单页 web 应用

    就是只有一个 web 页面的应用,
    是加载单个 HTML 页面,
    并在用户与应用程序交互时, 动态更新该页面的 web 应用程序

  • 区别

    • 对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面

    • 对于单页应用程序来说,

      只有第一次会加载页面,以后的每次请求,仅仅是获取必要的数据.然后,由页面中 js 解析获取的数据,展示在页面中

  • 单页面优势 :

    1. 减少了请求体积,加快页面响应速度,降低了对服务器的压力
    2. 更好的用户体验,让用户在 web app 感受 native app 的流畅, (局部刷新)
  • 单页面劣势 :

    1. 开发成本高 (需要学习路由)
    2. 不利于 SEO
  • 演示 : https://music.163.com/


零、路由介绍

  • 路由 : 是浏览器 URL 中的哈希值( // hash) 与 展示视图内容 之间的对应规则。
    • 简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
    • 当 URL 中的哈希值( // hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容
  • 为什么要学习路由?
    • 在 web App 中, 经常会出现通过一个页面来展示和管理整个应用的功能.
    • SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
  • vue 中的路由 : 是 hashcomponent 的对应关系, 一个哈希值对应一个组件

一、路由的基本使用

准备工作 (3个)

  • 安装npm i vue-router
  • 引入
<script src="./vue.js"></script>
// 千万注意 :引入路由一定要在引入vue之后,因为vue-router是基于vue工作的
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
  • 实例路由对象 + 挂载到vue上
    • 实例路由对象 : const router = new VueRouter()
    • 挂载到vue上 : new Vue({ router,data,methods })
    • 验证路由是否挂载成功, 就看打开页面,最后面有没有个 ///

具体步骤 (4个)

  • 1.入口
  • 2.路由规则
  • 3.组件
  • 4.出口
// 1. 入口
	 // 方式1 : url地址为入口   调试开发用
	 输入url地址 改变哈希值 `01-路由的基本使用.html///one`	
	 // 方式2 : 声明式导航 : router-link+to (见下面介绍)
     
// 2. 路由规则
// path : 路由路径 【path的属性值前面要加斜杠/。】
// component : 将来要展示的路由组件
routes: [
	// 【path的属性值前面要加斜杠/。】
    { path: '/one', component: One }, 
    { path: '/two', component: Two }
]

// 3. 组件
// 使用返回值的这个组件名称
const One = Vue.component('one', {
  template: ` <div> 子组件 one </div> `
})

// 4. 出口
<!--  出口 组件要展示的地方-->
<router-view></router-view>

// 总结
拿到入口哈希路径, 根据路由匹配规则,找到对应的组件,显示到对应的出口位置 

01-路由的基本使用.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
        准备工作 (3个)
        1. 安装路由 npm i vue-router
        2. 引入路由
        3. 实例化路由 + 挂载到vue上
        
        具体步骤 (4个)
        1. 入口  (哈希值) 手动在url上写  /one
        2. 规则  routes 
        3. 组件 
        4. 出口
    -->

    <div id="app">
        <!-- 第四步 : 出口 占位置 【出口router-view在哪里,就在哪里显示组件。】【vue-router.js中内置了vueRouter】 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 第三步 : 路由组件 【路由组件要写在路由实例对象前,否则报错。】
        const One = {
            template: `<div>one组件</div>`
        }

        // 实例化路由
        const router = new VueRouter({
            // 第二步 : 路由的匹配规则 一个哈希值 对应一个组件
            routes: [{
                path: '/one',
                component: One
            }]
        })

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

</html>

image-20200320094316086


二、路由使用注意事项

  • 入口
    • 最常用的入口 是 声明式导航 router-link
<!-- 
    router-link 组件最终渲染为 a标签, to属性转化为 a标签的href属性 
    to 属性的值 , 实际上就是哈希值,将来要参与路由规则中进行与组件匹配
    <a href="///one" class="">ONE</a>
-->
<router-link to="/one">首页</router-link>  
  • 组件
const One = {
  template: `<div> 子组件 one </div> `
}
  • 演示 : 多个组件匹配
<div id="app">
  <!-- 1 路由入口:链接导航 -->
  <router-link to="/one">One</router-link>
  <router-link to="/two">Two</router-link>

  <!-- 4 路由出口:用来展示匹配路由视图内容 -->
  <router-view></router-view>
</div>

<!--  导入 vue.js -->
<script src="./vue.js"></script>
<!--  导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
  // 3 创建两个组件
  const One ={
    template: '<h1>这是 one 组件</h1>'
  }
  const Two =  {
    template: '<h1>这是 two 组件</h1>'
  }

  // 0 创建路由对象
  const router = new VueRouter({
    // 2. 路由规则
    routes: [
      { path: '/one', component: One },
      { path: '/two', component: Two }
    ]
  })

  const vm = new Vue({
    el: '//app',
    //0. 不要忘记,将路由与vue实例关联到一起!
    router
  })
</script>

02-多个路径.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
        准备工作
        1. 安装
        2. 引入
        3. 实例化+挂载

        具体步骤
        1. 入口
        2. 规则
        3. 组件
        4. 出口
    -->

    <div id="app">
        <!-- 第一步 : 入口 
            1. 刚才手动写 测试.开发时候用   /one   /two
            2. 声明式导航
        -->

        <!-- 
            router-link 声明式导航 
            router-link 最终会编译成 a 标签 
            to 转化为href 
            作用 : 改变入口的哈希值路径
        -->

        <!-- 最后编译成 <a href="///one" class="">ONE</a> -->
        <router-link to="/one">ONE</router-link>
        <!-- <router-link to="/two">TWO</router-link> -->

        <!-- 第四步 :出口 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 第三步 : 组件
        const One = {
            template: `<div>one组件</div>`
        }
        const Two = {
            template: `<div>two组件</div>`
        }

        // 实例化路由
        const router = new VueRouter({
            // 规则
            routes: [{
                path: '/one',
                component: One
            }, {
                path: '/two',
                component: Two
            }]
        })

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

</html>

三、入口导航菜单高亮处理

  • 点击导航 => 元素里添加了两个类
<a href="///one" class="router-link-exact-active router-link-active">One</a>
<a href="///two" class="">Two</a>
  • 修改方式1 : 直接修改类的样式
.router-link-exact-active,
.router-link-active {
  color: red;
  font-size: 50px;
}

  • 修改方式2 : 使用存在过的类样式 => 修改默认高亮类名
const router = new VueRouter({
  routes: [],
  // 修改默认高亮的a标签的类名
  // red 是已经存在过的
  linkActiveClass: 'red'
})


03-高亮状态.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>

    <style>
        /* 假如说路由是后面加进来的, 但是如果之前就已经有了一个类 */
        
        .red {
            color: red;
            font-size: 50px;
        }
        /* 
        .router-link-exact-active,
        .router-link-active {
            color: red;
            font-size: 50px;
        } 
        */
    </style>
</head>

<body>
    <div id="app">
        <!-- 1. 入口 -->
        <router-link to="/one">one</router-link>
        <router-link to="/two">two</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>
    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const One = {
            template: `<div>one组件</div>`
        }
        const Two = {
            template: `<div>two组件</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/one',
                component: One
            }, {
                path: '/two',
                component: Two
            }],
            // router-link-exact-active 【去掉router-,改为小驼峰,最后加上Class。】
            linkExactActiveClass: 'red'
        })

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

</html>


04-高亮状态-精确匹配和模糊匹配.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>

    <style>
        /* 假如说路由是后面加进来的 ,但是如果之前就已经有了一个类 */
        /* .red {
            color: red;
            font-size: 50px;
        } */
        
        .router-link-exact-active,
        .router-link-active {
            color: red;
            font-size: 50px;
        }
    </style>
</head>

<body>
    <!-- 
       1. 精确匹配  和 模糊匹配  (了解)
       2. router-link-exact-active: 精确匹配   当url上的路径 == href的值 
       3. router-link-active      : 模糊匹配   当url上的路径 (包含)>=  href的值
     -->

    <div id="app">
        <!-- 1. 入口 -->
        <!-- exact:加上表示只允许精确匹配,不允许模糊匹配 【只需给没有精确路由的router-link 加上 exact 即可。】-->
        <router-link to="/" exact>one</router-link>
        <router-link to="/two">two</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const One = {
            template: `<div>one组件</div>`
        }
        const Two = {
            template: `<div>two组件</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                    path: '/',
                    component: One
                }, {
                    path: '/two',
                    component: Two
                }]
                // router-link-exact-active
                // linkExactActiveClass: 'red'
        })

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

</html>


四、路由配置

4.1 动态路由 => 详情列表

导入 : 列表三个手机都要点击进去详情页, 只需要一个组件,显示不同的数据即可

// 入口
<router-link to="/detail/1">手机1</router-link>
<router-link to="/detail/2">手机2</router-link>
<router-link to="/detail/3">手机3</router-link>

<router-link to="/detail">手机4</router-link>  没有参数如何????

// 规则
routes: [
  // 2 . 路由规则
  { path: '/detail/:id?', component: Detail }
]

// 获取参数的三种方式
const Detail =  {
    template: `
        // 方式1 : 组件中直接读取  
        //【$route:当前路由】
        <div> 显示详情页内容....{{ $route.params.id  }} </div>
    `,
    created() {
        // 方式2 : js直接读取
        // 打印只会打印一次,因为组件是复用的,每次进来钩子函数只会执行一次  
        // 【$route:当前路由】
        console.log(this.$route.params.id)
    },
    // 方式3 : 监听路由的参数,为什么不需要深度监听,因为一个路径变化,就会对应一个对新的路由对象(地址变)
    watch: {
        $route(to, from) {
            console.log(to.params.id)
        }
    }
}


05-动态路由-详情页.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
       动态路由
       1. 使用参数接收不同的路由参数  
        path ='/detail/:id'  
       2. 参数可传可不传  path ='/detail/:id?' 
     -->

    <div id="app">
        <!-- 1. 入口 -->
        <router-link to="/detail/1">手机1</router-link>
        <router-link to="/detail/2">手机2</router-link>
        <router-link to="/detail/3">手机3</router-link>
        <router-link to="/detail">手机4</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const detail = {
            // 经测试,在生命周期钩子函数中,要使用$route,前面得加this. ,否则报错,因为是事件;而在组件的其他地方,可加可不加
            template: `<div>详情页组件 {{ $route.params.id }}</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/detail/:id?',
                component: detail
            }]
        })

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

</html>


4.2 路由对象 - $route

image-20200320145914241

image-20200320150335970

image-20200320152559208


  • 一个路由对象 (route object) :表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息

  • 一个哈希值路径 ==> 一个路由对象

  • $route.path

    • 类型: string
    • 字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"
    • // 后面、?前面的内容
  • $route.params

    • 类型: Object
    • 一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
  • $route.query

    • 类型: Object
    • 参数对象
    • 一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。
  • $route.hash

    • 类型: string

      当前路由的 hash 值 (带 //) ,如果没有 hash 值,则为空字符串。

  • $route.fullPath

    • 类型: string
    • 全路径
    • 完成解析后的 URL,包含查询参数和 hash 的完整路径。
// 演示 : 
<router-link to="/detail/4?age=21//one">detail</router-link>
{ path: '/detail/:id?', component: detail } 
在组件内 created打印 this.$route
> fullPath: "/detail/4?id=001//one"
> hash : "//one"
> params : {id:'4'}
> query : {age : 21}
> path : '/detail/4'


06-$route.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
       $route:路由对象,解析的url信息,哈希值的url信息
       哈希值 (#/one/4?age=30#aaa) ==> $route 
     -->
    <div id="app">
        <!-- 1. 入口 -->
        <!-- <router-link to="/one/4?age=30#aaa">one</router-link> -->
        <router-link to="/one/1">第一个</router-link>
        <router-link to="/one/2">第二个</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const One = {
            template: `<div>one组件 {{ $route.params.id }}</div>`,
            // 经测试,在生命周期钩子函数中,要使用$route,前面得加this. ,否则报错,因为是事件;而在组件的其他地方,可加可不加
            created() {
                // 页面加载过程中的第一次的值,不会变化,因为created只执行一次
                console.warn(this.$route.params.id)
            },
            // 补充mounted、updated
            // mounted不能监听到 this.$route.params.id 的变化
            mounted() {
                console.log('mounted中的id是---', this.$route.params.id)
            },
            // updated能监听到 this.$route.params.id 的变化
            updated() {
                console.log('updated中的id是---', this.$route.params.id)
            },
            // 很重要的思想(★)
            // 使用watch 监听 $route 路由对象,获取里面的信息 【url变了,$route跟着变。之前监听复杂类型时,是复杂类型的地址没变,只是它里面的数据变化了而已。】
            watch: {
                $route(newVal) {
                    console.warn(newVal)
                    console.warn(newVal.params.id)
                }
            }
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/one/:id',
                component: One
            }]
        })

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

</html>


4.3 嵌套路由/子路由: children

导入 : url测试 parent 和child, 想让child 在 parent 中显示

  • parent 的内部 添加 : <router-view> </router-view>
  • 规则里添加 children
  • /child 和 child 的区别
    • 如果是/child => 那么访问就可以直接访问///child就可以访问 子组件
    • 如果是child => 那么访问就应该访问///parent/child才可以访问子组件
const parent = {
    template: `<p>parent  <router-view> </router-view> </p>`
}
const child = {
    template: `<p>child</p>`
} 

const router = new VueRouter({
    routes: [
        {
            path: '/parent',
            component: parent,
            children: [
                { path: '/child', component: child }
            ]
        }
    ]
})


07-嵌套路由.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 1. 入口 -->
        <!-- 
            需求: child组件 放到 parent组件 里面
            办法: children: [路由规则]
        -->

        <!-- 4. 出口 -->
        <router-view></router-view>
        <hr />
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    
    <script>
        // 3. 组件
        const parent = {
            template: `<div> parent组件 -- <router-view></router-view> </div>`
        }

        const child = {
            template: `<div>child组件</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/parent',
                component: parent,
                children: [{
                    // 子组件的path值前,加斜杆/,则浏览器的url中不需要写成 /parent/child,直接写/child即可。不加的话,就要写成 /parent/child
                    path: '/child',
                    component: child
                }],
                // children: [{
                //     path: 'child',
                //     component: child
                // }]

                //  path : '/child'    => 哈希值 : /child
                //  path : 'child'     => 哈希值 : /parent/child
            }]
        })

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

</html>


4.4 命名路由 ==> :to="{ name : 'xxx' }"

  • 有时候,通过一个名称来标识一个路由显得更方便一些,
  • 特别是在链接一个路由,或者是执行一些跳转的时候。 ===> 场景
  • 你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。 ==> 如何命名
// 命名
routes: [
    {
        path: '/parent',
        name: 'parent',
        component: parent
    }
]

// 入口链接 + 跳转  (使用 path 和 name 的转换)
<!-- 方式1 : url手动写 -->

<!-- 方式2 : 入口链接 声明式导航 -->
<router-link to="/parent">点击</router-link>
<router-link :to="{ name : 'parent' }">点击</router-link>  // 忘了 带 : 原始对象类型

<!-- 方式3 : 编程式导航 -->
 fn() {
     // this.$router.push('/parent')
     this.$router.push({
         name: 'parent'
     })
 }


09-命名路由.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 1. 入口 -->
        <!-- 下面两个用的都是 path -->
        <!-- 
            <router-link to="/one">one</router-link>
            <router-link to="/two">two</router-link> 
        -->
        <!-- to前面不加冒号,就会把属性值当做字符串 -->
        <router-link :to="{ name : 'one' }">one</router-link>
        <router-link :to="{ name :'two' }">two</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>

    <script>
        // 3. 组件
        const One = {
            template: `<div>one组件</div>`
        }
        const Two = {
            template: `<div>two组件</div>`,
            created() {
                console.log(this.$route.name)
            }
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/one',
                name: 'one',
                component: One
            }, {
                path: '/two',
                name: 'two',
                component: Two
            }]
        })

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

</html>


4.5 命名视图:

导入 : 有时候想同时 (同级) 展示多个视图,

需求 : 访问 / 根目录 同时展示以下三个组件

  • 三个组件
const header = {
    template: `<p>header  </p>`
}
const main = {
    template: `<p>main  </p>`
}
const footer = {
    template: `<p>footer  </p>`
}

  • 规则
// 以前的那个方式只能显示三个 header
// 演示之前的效果 

routes: [
    {
        path: '/',
        components: {
            default: header,
            m: main,
            f: footer
        }
    }
]

  • 出口
<router-view> </router-view>
<router-view name="m"> </router-view>
<router-view name="f"> </router-view>


08-命名视图.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
       需求 :  /  => 三个组件 header main footer
     -->
    <div id="app">
        <!-- 4. 出口 -->
        <router-view></router-view>
        <router-view name="m"></router-view>
        <router-view name="f"></router-view>
    </div>
    
    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const header = {
            template: `<div>header组件</div>`
        }
        const main = {
            template: `<div>main组件</div>`
        }
        const footer = {
            template: `<div>footer组件</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [{
                path: '/',
                components: {
                    default: header,
                    m: main,
                    f: footer
                }
            }]
        })

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

</html>


4.6 重定向

方式1:
redirect: '/header'

方式2:
redirect: { name: 'header' }

方式3:【函数,用路由对象去判断, to:即路由对象$route。】
redirect: to => {
      // console.log(to)
    return {
        name: 'about'
    }
}


10-重定向.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 1. 入口 -->
        <!-- <router-link to="/one">one</router-link> -->

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>
    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const One = {
            template: `<div>one组件</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则
            routes: [
                // 方式1 : path路径
                {
                    path: '/',
                    redirect: '/one'
                },

                // 方式2 : 路由的名称
                {
                    path: '/',
                    redirect: {
                        name: 'one'
                    }
                },

                // 方式3 : 函数,用路由对象去判断
                {
                    path: '/',
                    // to:即路由对象$route
                    redirect: to => {
                        // console.log(to) // to:即路由对象$route
                        //  if (to.XXX) {
                        //    return { name : 'one'}
                        //  } else {
                        //    return {name : 'two' }
                        //  }

                        return {
                            name: 'one'
                        }
                    }
                }, {
                    path: '/one',
                    name: 'one',
                    component: One
                }
            ]
        })

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

</html>


4.7 【路由给】组件传参

【路由给组件传参】

  • 原始方式使用 $route获取
// 入口
<router-link to="/header/3">123</router-link>

// 规则
routes: [
    {
        path: '/header/:id',
        component: header,
    }
]

// 获取参数
const header = {
    template: `<p>header  {{ $route.params.id }}  </p>`
}

  • 布尔模式
// 入口
<router-link to="/header/3">123</router-link>

// 规则
routes: [
    {
        path: '/header/:id',
        component: header,
        // 如果 props 被设置为 true,route.params 将会被设置为组件属性
        props: true
    }
]

// 获取参数
const header = {
    // 参数 id 当成参数
    props: ['id'],
    template: `<p>header   {{ id }} </p>`
}

  • 对象模式
// 入口
 <router-link to="/header">123</router-link>

// 规则
 routes: [
     {
         path: '/header',
         component: header,
         props: { foo: '0000' }
     }
 ]
// 组件
 const header = {
        props: ['foo'],
        template: `<p>header   {{ foo }} </p>`
 }

  • 函数模式
// 同对象模式一样
// 区别是props值不一样
 props: to => {
     return { foo: '0000' }
 }

  • 注意 : 对象模式和函数模式参数 在props里,所以声明式导航那里就不要传参了

11-组件传参.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
       方式1:to='/one/4'  path='/one/:id?'  
              组件:$route.params.id 
              事件:this.$route.params.id 

       方式2: 布尔模式  
              路由规则里,写props:true     
              将参数id 作为组件的属性存在  
              -  props: true
              - 组件内 : props:['id']
              - 使用: {{ id }}

       方式3: 对象模式      
              - props : { aaa : 'bbb' }
              - props: ['aaa']
              - {{ aaa }}

        方式4 :  函数模式    
               - props : to => { return { aaa : 'ccc' }  }
               - props:['aaa']
               - {{ aaa }} 
    -->

    <div id="app">
        <!-- 1. 入口 -->
        <!-- <router-link to="/one/11">one</router-link> -->
        <router-link to="/one">one</router-link>

        <!-- 4. 出口 -->
        <router-view></router-view>
    </div>
    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        // 3. 组件
        const One = {
            props: ['id', 'aaa'],
            template: `<div>one组件 {{ aaa }}</div>`
        }

        //  实例化
        const router = new VueRouter({
            // 2. 规则

            routes: [
                // props : true  将id参数作为组件的属性存在
                // {
                //     path: '/one/:id',
                //     component: One,
                //     props: true
                // }

                // 将aaa 作为 组件的属性存在
                // {
                //     path: '/one',
                //     component: One,
                //     props: {
                //         aaa: 'bbb'
                //     }
                // }

                // 函数
                {
                    path: '/one',
                    component: One,
                    props: to => {
                        return {
                            aaa: 'ccc'
                        }
                    }
                }
            ]
        })

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

</html>


五、路由进阶

5.1 元信息

  • **作用 **
在路由导航的时候,可以用作判断

  • 规则声明
 routes: [
     {
         path: '/header',
         component: header,
         // (1)meta默认是空对象;(2)可以控制组件的显示与隐藏
         meta: {
            title: 'XXXX'
         }
     }
 ]

  • 获取
 created() {
    document.title = this.$route.meta.title
 }


01-元信息.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
        3个准备工作
        4个具体步骤

        元信息 : 路由里添加 meta 字段 
    -->

    <div id="app">
        <router-view></router-view>
        <h1 id="haha">哈哈</h1>
        <h1>嘿嘿</h1>
    </div>

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>

    <script>
        //组件
        const One = {
            template: `<div>one组件</div>`,
            created() {
                // 有了这个meta 可以做很多事情
                // console.log(this.$route.meta.title)
                // 可以设置标题
                document.title = this.$route.meta.title
                console.log(document.querySelector('//haha').innerHTML) // 哈哈
                console.log(111) // 111
            }
        }

        const Two = {
            template: `<div>two组件</div>`,
            created() {
                document.title = this.$route.meta.title
            }
        }

        // 实例化 + 挂载
        const router = new VueRouter({
            routes: [{
                path: '/one',
                name: 'one',
                component: One,
                meta: {
                    title: '帅气的马哥'
                }
            }, {
                path: '/two',
                name: 'two',
                component: Two,
                meta: {
                    title: '骚气的春春'
                }
            }]
        })

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

</html>

image-20200321083610233


5.2 编程式导航

const one = {
    template: ` 
<div> <button @click="handleClick('back')">返回 上一页</button>
<button @click="handleClick('push')">跳转 two页</button>
<button @click="handleClick('replace')">替换 two页</button> 
</div>`,
    methods: {
        handleClick(type) {
            if (type == 'back') {
                // 返回
                this.$router.back()
            } else if (type == 'push') {
                // 跳转 有历史记录
                this.$router.push('/two')
            } else {
                // 替换 没有历史记录
                this.$router.replace('/two')
            }
        }
    }
}
const two = {
    template: `<p>two </p>`
}


02-编程式导航.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
      入口 
      1. 手动url修改   /one
      2. 声明式导航  <router-link to='/one'>one</router-link>

      3. 编程式导航  this.$router.push('/one')
          (1)前进(跳转) ==> 
            - this.$router.push()    - 有记录 【可以后退】
            - this.$router.replace() - 没有记录 【不可以后退】
          (2)返回   ====> this.$router.back()
    -->

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

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    <script>
        //组件
        const One = {
            template: `<div> one组件
                <button @click="handle('push')"> 跳转到two - push </button>
                <button @click="handle('back')"> 返回到/ </button>
                <button @click="handle('replace')"> 跳转到two - replace </button>
            </div>`,

            methods: {
                handle(type) {
                    if (type == 'push') {
                        // $route: 路由对象,解析url信息 (属性:.path、 .name、 .meta、 .params)
                        // $router: VueRouter的路由实例【 也就是下面的const router = new VueRouter(...)的变量router 】,挂载到vue实例上后,就是$router,用于编程式导航 (方法 ) 
                        // push => 有记录的 【这里的push是vue的跳转,不是原生js的】
                        this.$router.push('/two')
                    } else if (type == 'back') {
                        this.$router.back()
                    } else if (type == 'replace') {
                        // replace => 没有记录的
                        this.$router.replace('/two')
                    }
                }
            }
        }

        const Two = {
            template: `<div>two组件</div>`
        }

        // 实例化 + 挂载
        const router = new VueRouter({
            routes: [{
                path: '/one',
                name: 'one',
                component: One
            }, {
                path: '/two',
                name: 'two',
                component: Two
            }]
        })

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

</html>


5.3 导航守卫

router.beforeEach((to, from, next) => {
    // 访问 login

    if (to.name == 'login') {
        // 下一步
        next()
    } else {
        // 停止跳转
        next(false)
        // 跳转到下一步
        next({ name: 'login' }) 或者 使用路径  next('/login')
    }
})


03-导航守卫.html

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

<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>

<body>
    <!-- 
        导航守卫   : 是通过跳转或者取消的方式守卫导航   A => 导航守卫 =>  B

        需求 : 所有的页面经过登录 之后才准访问
            1.  =>  login   可以
            2.  =>  one    =>  访问login => 登录之后 => one

        前置导航守卫   beforeEach   
        概念 :  是通过跳转或者取消的方式守卫导航   拦截
        1. 写法  router.beforeEach( (to,from ,next)=> {} )
        2. to : 目标路由对象  from : 来源路由对象  next: 下一步
        3. next() 允许下一步
            next(false) 不允许
            next('/login')  跳转到login    
    -->

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

    <script src="./vue.js"></script>
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>

    <script>
        //组件
        const One = {
            template: `<div>one组件</div>`
        }
        const Login = {
            template: `<div>Login组件</div>`
        }

        // 实例化 + 挂载
        const router = new VueRouter({
            routes: [{
                path: '/one',
                name: 'one',
                component: One
            }, {
                path: '/login',
                name: 'login',
                component: Login
            }]
        })

        // 导航守卫
        // /one => /login
        // to : 目标路由对象($route)
        // from : 来源路由对象
        // next():下一步 【不写next(),就不能访问下一步。】
        router.beforeEach((to, from, next) => {
            // console.log('from:', from)
            console.log('to:', to)

            // 如果访问 login => 允许访问 next 【用to.name、to.path都可以。】
            if (to.name == 'login') {
                next() //  next()中不用传递路径 '/login',否则会无限循环,直到报错。
            } else if (to.name == 'one') {
                next()
            } else {
                next(false); // 不允许访问,next(false) 和不写任何代码的结果一样
                // next('/login'); // 如果不是login => 转到 login
                // next({ name: 'login' })
            }
        })

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

</html>

posted on 2020-03-31 15:33  冲啊!  阅读(424)  评论(0编辑  收藏  举报

导航