Vue route

Vue 路由

对于大多数单页面应用,都推荐使用官方支持的 vue-router 库

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

安装

CDN

https://unpkg.com/vue-router/dist/vue-router.js

导入即可

<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>

路由基本使用

用 Vue.js + Vue Router 创建单页应用,是非常简单的。使用 Vue.js ,我们已经可以通过组合组件来组成应用程序,当你要把 Vue Router 添加进来,我们需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">

</div>

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

<script>
    // 如果以后是模块化编程,Vue.proptotype.$VueRoute = VueRoute
    // Vue.use(VueRouter);

    const Course = {
        data: function () {
            return {}
        },
        template: `<div>我是免费课程</div>`
    };

    const Home = {
        data: function () {
            return {}
        },
        template: `<div>我是首页</div>`
    };

    // 创建路由
    const router = new VueRouter({
        mode: 'history',
        // 定义路由规则
        routes: [
            {path: '/', redirect: 'home'},
            {path: "/home", component: Home},
            {path: "/course", component: Course},
        ]
    });

    let App = {
        data: function () {
            return {}
        },
        // router-link和router-view是vue-router提供的两个全局组件
        // router-view路由组件出口
        template: `
            <div>
                <div class="header">
                    <router-link to="/home">首页</router-link>
                    <router-link to="/course">免费课程</router-link>
                </div>
                    <router-view></router-view>
            </div>
        `,
    };

    let vm = new Vue({
        el: '#app',
        // 挂载路由
        router,
        data: function () {
            return {}
        },
        template: `
            <App />
        `,
        components: {
            App
        }
    })
</script>

</body>
</html>

重定向和别名

重定向

重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
})

重定向的目标也可以是一个命名的路由:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})

甚至是一个方法,动态返回重定向目标:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目标路由 作为参数
      // return 重定向的 字符串路径/路径对象
    }}
  ]
})

注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在下面这个例子中,为 /a 路由添加一个 beforeEachbeforeLeave 守卫并不会有任何效果。

其它高级用法,请参考例子

别名

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

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

上面对应的路由配置为:

const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})

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

命名路由

有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    }
  ]
})

要链接到一个命名路由,可以给 router-linkto 属性传一个对象:

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

这跟代码调用 router.push() 是一回事:

router.push({ name: 'user', params: { userId: 123 }})

这两种方式都会把路由导航到 /user/123 路径。

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {
    data: function () {
        return {}
    },
    template: `<div>我是用户</div>`,
};

// 创建路由
const router = new VueRouter({
    // mode: 'history',
    // 定义路由规则
    routes: [
        {
            // 动态路径参数 以冒号开头
            path: "/user/:id",
            component: User,
            name: 'User'
        },
    ]
});

现在呢,像 /user/foo/user/bar 都将映射到相同的路由。

一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输出当前用户的 ID:

let App = {
    // router-link和router-view是vue-router提供的两个全局组件
    // router-view路由组件出口
    template: `
        <div>
            <div class="header">
            	<router-link v-bind:to="{name:'User',params:{id:1}}">用户1</router-link>
            </div>
            <router-view></router-view>
        </div>
`
};

你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:

模式 匹配路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

除了 $route.params 外,$route 对象还提供了其它有用的信息,例如,$route.query (如果 URL 中有查询参数)、$route.hash 等等。你可以查看 API 文档 的详细说明

响应路由参数的变化

提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应...
    }
  }
}

或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

动态路由实例

$route:为当前User对象 继承父类

$router:为路由对象 VueRouter

const User = {
    data: function () {
        return {
            user_id: null
        }
    },
    template: `<div>我是用户{{ user_id }}</div>`,
    /* 提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。
        因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效 */
    watch: {
        // 路由对象信息
        '$route': function (to, from) {
            // 对路由变化作出响应...
            console.log(to.params.id);
            console.log(from);
            this.user_id = to.params.id
            // 发送ajax
        }
    }
};

// 创建路由
const router = new VueRouter({
    // mode: 'history',
    // 定义路由规则
    routes: [
        {
            path: "/user/:id",
            component: User,
            name: 'User'
        },
    ]
});

image-20191227163014791

编程式导航vs声明式导航

声明式导航

<router-link v-bind:to="{name:'User',params:{id:1}}">用户1</router-link>
<router-link v-bind:to="{name:'User',params:{id:2}}">用户2</router-link>

编程式导航

除了使用 `` 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。

router.push(location, onComplete?, onAbort?)

注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(...)

声明式 编程式
<router-link :to="..."> router.push(...)

该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:

// 字符串
router.push('home')

// 对象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

注意:如果提供了 pathparams 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path

const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

同样的规则也适用于 router-link 组件的 to 属性。

在 2.2.0+,可选的在 router.pushrouter.replace 中提供 onCompleteonAbort 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。在 3.1.0+,可以省略第二个和第三个参数,此时如果支持 Promise,router.pushrouter.replace 将返回一个 Promise。

注意: 如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个 /users/1 -> /users/2),你需要使用 beforeRouteUpdate 来响应这个变化 (比如抓取用户信息)。

router.replace(location, onComplete?, onAbort?)

router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。

声明式 编程式
<router-link :to="..." replac router.replace(...)

router.go(n)

这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)

例子

// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)

// 后退一步记录,等同于 history.back()
router.go(-1)

// 前进 3 步记录
router.go(3)

// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)

操作 History

你也许注意到 router.pushrouter.replacerouter.gowindow.history.pushStatewindow.history.replaceStatewindow.history.go好像, 实际上它们确实是效仿 window.history API 的。

因此,如果你已经熟悉 Browser History APIs,那么在 Vue Router 中操作 history 就是超级简单的。

还有值得提及的,Vue Router 的导航方法 (pushreplacego) 在各类路由模式 (historyhashabstract) 下表现一致。

一个例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">

</div>

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

<script>
    // 如果以后是模块化编程,Vue.proptotype.$VueRoute = VueRoute
    // Vue.use(VueRouter);

    // 路由模式:(路由范式)
    // http://127.0.0.1:80/index/user
    // http://127.0.0.1:80/user/1
    // http://127.0.0.1:80/user?user_id=1

    const Home = {
        data: function () {
            return {}
        },
        template: `<div>我是首页</div>`
    };

    const User = {
        data: function () {
            return {
                user_id: null
            }
        },
        template: `<div>我是用户{{ user_id }}
                    <button v-on:click="chickHandler">跳转首页</button>
        </div>`,
        methods: {
            // 编程式导航
            chickHandler: function () {
                this.$router.push({
                    name: "Home"
                })
            }
        },
        /* 提醒一下,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。
        因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效 */
        watch: {
            // 路由对象信息
            '$route': function (to, from) {
                // 对路由变化作出响应...
                this.user_id = to.params.id
                // 发送ajax
            }
        }
    };

    // 创建路由
    const router = new VueRouter({
        // mode: 'history',
        // 定义路由规则
        routes: [
            {
                path: "/user/:id",
                component: User,
                name: 'User'
            },
            {
                path: "/home",
                component: Home,
                name: 'Home',
            }
        ]
    });

    let App = {
        data: function () {
            return {}
        },
        // router-link和router-view是vue-router提供的两个全局组件
        // router-view路由组件出口
        template: `
            <div>
                <div class="header">
                    <router-link v-bind:to="{name:'User',params:{id:1}}">用户1</router-link>
                    <router-link v-bind:to="{name:'User',params:{id:2}}">用户2</router-link>
                </div>
                    <router-view></router-view>
            </div>
        `,
    };

    let vm = new Vue({
        el: '#app',
        router,
        data: function () {
            return {}
        },
        template: `
            <App />
        `,
        components: {
            App
        }
    })
</script>

</body>
</html>
posted @ 2019-12-27 16:49  Hyyyy  阅读(284)  评论(0编辑  收藏  举报