vue router.js

下载:vue-router.js

该文件依赖于vue.js

<script src="Scripts/vue-2.4.0.js"></script>   
<script src="/Scripts/vue-router.js"></script>
路由的作用

使用路由后,当前页面的url地址就会多出一个#号,这个#号与html页面的锚点类似,在route.js中它表示根据路由对象里的路由配置在页面中切换不同的路由组件以便展示在客户端显示。路由发起的请求会交给router对象进行处理后返回请求的资源而不是直接向服务端发起资源请求,使用路由的好处在于发起一个路由请求后浏览器地址栏的刷新按钮并不会动,而常规的超链接请求会使页面刷新。虽然两者都是向服务端发起请求,但router的路由机制可以将客户端请求所需要的vue组件静态加载(不刷新地址栏)到当前页面上显示。

创建路由对象
<template id="loginTem">
    <div>登录区域</div>
</template>

<template id="registerTem">
    <div>注册区域</div>
</template>

<script>
    //客户端路由总是与组件有关,所以首先创建组件
    var loginCom={
        template:"#loginTem"
    }

    var registerCom={
        template:"#registerTem"
    }

    var router = new VueRouter({
        //路由对象的routes属性是一个集合,用于设定路由模板
        routes: [            
            { path: "/login", component: loginCom }, //路由模板,用于匹配客户端路由请求,component在此处是外部的组件被注册在路由中,称为路由组件
            { path: "/register", component: registerCom } //不同的路由模板对不同的路由请求进行匹配
        ]
    });
</script>
路由的运作过程

当在vue对象所监视的html中的超链接、按钮等元素的点击事件上发起一个客户端路由请求后,这个请求会通过vue转发到路由对象上(路由对象会在vue中注册),路由对象根据routes集合里的路由模板对路由地址请求进行路由匹配,匹配成功后就将注册在路由模板里的组件发送到客户端显示在html文档上。

路由标签

组件切换可以使用component标签,通过指定它的is属性来切动态换组件,而路由组件的切换则是通过vue-router提供两个html标签来实现

router-view

这个标签是路由组件的容器,路由匹配的过程是:一旦浏览器发起路由请求,那么vue对象就会截获这个请求,再将请求转交给路由模板进行匹配,匹配成功后会将对应的路由组件插入到router-view容器里。所以,如果仅仅是发起了路由请求,但没有设置router-view,那么路由组件是不会显示出来的。

<div id="box">
    <a href="#/login">login</a>
    <a href="#/register">register</a>
    <router-view></router-view> //组件已经被注册为路由组件,此处不再以组件标签名而是使用路由标签来插入html文档,vue的整个路由机制就是围绕这个标签做文章,针对不同的路由匹配展示不同的路由组件到这个router-view里面去。
</div>

<template id="loginTem">
    <div>登录区域</div>
</template>

<template id="registerTem">
    <div>注册区域</div>
</template>

<script>
    //客户端路由总是与组件有关,所以首先创建组件
    var loginCom={
        template:"#loginTem"
    }

    var registerCom={
        template:"#registerTem"
    }

    var router = new VueRouter({
        //路由对象的routes属性是一个集合,用于设定路由模板
        routes: [            
            { path: "/login", component: loginCom }, //路由模板,用于匹配客户端路由请求
            { path: "/register", component: registerCom } //不同的路由模板对不同的路由请求进行匹配
        ]
    });

    var vm = new Vue({
        el: "#box",
        router: router //将路由对象注册到vue对象的router属性中,使vue对象可以监听到它内部所包含的html元素的url请求的路由变化,然后调用路由对象对路由请求进行匹配
    });
</script>

router-link

可以替代a标签,属性to指向目标路由地址。其作用是发起路由请求,有三种方式可以发起路由请求,1.点击router-link或a标签,2.直接在浏览器地址栏输入路由地址,3.通过手动写js程序发起路由请求。
<div id="box">
    <router-link to="/login" >登录</router-link> //可以添加tag属性,如tag="div",这样会把router-link渲染成div,且依然可以点击
    <router-link to="/register">注册</router-link>   
    <router-view></router-view>
</div>

控制<router-link>的css

var router = new VueRouter({
    routes: [
      ……
    ],
    linkActiveClass: "link-active"
});
.link-active {
    background: #ffd800;
    color: #fff;
} 
手动定向路由 redirect
routes: [
    {path:"/",redirect:"/login"}, //当首次显示主页时直接定向到登录区域,或直接{path:"/",component:"loginCom"}使请求主页时直接显示登录区域
    { path: "/login", component: loginCom }, 
    { path: "/register", component: registerCom }
]
路由命名 name
{path:"/index/productList",component:productList,name:"productList"}
手动发起路由请求 $router.push()

使用$router.push()方法,注意不是$route而是$router,给路由命名后,可以通过点击事件手动发起路由请求并传递url路由查询字符串

<div @click="redirect" > 商品购买</div >
methods: {
    redirect: function() {
        this.$router.push({ name: "productList",params:productID });
       //或
        this.$router.push("/index/productList"+productID);
       //或
        this.$router.push({path:"/index/productList"+productID});
    }
}
路由匹配中的查询字符

非严格匹配 $route.query

路由地址的后面跟上查询字符串能够被识别有效路由。比如请求的路由为#/login,路由模板也可以匹配#/login?id=100&name=sam。可以在组件对象的内部通过组件创建完成之后触发的事件、使用$route.query获取查询字符串的值

<router-link to="/login?id=100&name=sam">登录</router-link>
//当前组件被初始化时打印路由地址中的查询字符
var login={
    template: "#loginTem",
    created: function () {
        console.log(this.$route.query.id);
    }
}

严格匹配 $route.params

在路由模板里可以定义查询字符的匹配规则,如果在路由模板里定义了查询字符的匹配的规则,那么就必须包括查询字符在内的路由地址得完全符合路由模板的规则,否则不会被匹配。比如在路由模板中指定了查询字符,此时#/login地址与#/login/100/sam两个地址只有后一个会被匹配成功。可以在组件对象的内部通过组件创建完成之后触发的事件、使用$route.params获取查询字符串的值

<router-link to="/login/100/sam" >登录</router-link>
var router = new VueRouter({   
    routes: [       
        { path: "/login/:id/:name", component: loginCom },  //这个路由模板只绝对匹配/login/id/name的路由请求,/login/100/sam/leo将不会被匹配
    ]
});

//当前组件被初始化时打印路由地址中的查询字符
var login={
    template: "#loginTem",
    created: function () {
        console.log(this.$route.params.id);
    }
}

获取路由地址 $route.path

$route.path获取的地址不包括查询字符串

methods: {
    btnClick: function () {
        console.log(this.$route.path);
    }
}
监听路由

参考watch:vue-watch

子路由组件

下图中的账户是一个路由组件,而账户路由组件里面又插入了登录和注册路由组件。

<div id="box">
    <router-link to="/account">账户</router-link>
    <router-view></router-view> //切换账户模块和其它模块的路由组件容器
</div>

<template id="tem">
    <div class="module-box">
        <p>账户模块</p>
        <router-link to="/account/login">登录</router-link>
        <router-link to="/account/register">注册</router-link>
        <router-view></router-view> //切换账户模块下的登录和注册模块的子路由组件容器
    </div>
</template>

<template id="login">
    <div class="form-group">
        <label>
            用户:<input type="text" class="form-control" />
        </label>
        <label>
            密码:<input type="text" class="form-control" />
        </label>
        <button class="btn btn-primary">OK</button>
    </div>
</template>

<template id="register">
    <div class="form-group">
        <label>
            用户:<input type="text" class="form-control" />
        </label>
        <label>
            密码:<input type="text" class="form-control" />
        </label>
        <label>
            电邮:<input type="text" class="form-control" />
        </label>
        <button class="btn btn-primary">OK</button>
    </div>
</template>

</body>
</html>
<script>
    var router = new VueRouter({
        routes: [
            {
                path: "/account",
                component: { template: "#tem" },
                //在路由模板里添加子路由模板
                children: [
                    { path: "login", component: { template: "#login" } },
                    { path: "register", component: { template: "#register" } }
                ]
            }
        ]
    });

    var vm = new Vue({
        el: "#box",
        data: {
            msg:"hello"
        },
        router:router
    });
</script>

注意如果一个路由组件里嵌套了其它的路由组件,那么必须在路由匹配规则的父规则里使用children指定嵌套在父路由里的子路由,那么这种关系必须使用children指定,如果你把子路由匹配规则放在父路由规则的外面,那么当你点击router-link发起子路由请求后,父路由组件会被切换掉,看不见。也即你想在切换路由的时候父路由必须显示出来,就必须指定children。只有指定了children属性才使嵌套的路由组件成为父子关系。

如果要让页面一加载就显示其中某个子路由,可以利用redirect实现

{
    path: "/account",
    component: { template: "#tem" },
    redirect: "/account/login",
    children: [
        { path: "login", component: { template: "#login" } },
        { path: "register", component: { template: "#register" } }
    ]
}

//带查询字符串的默认子路由
{
    path: "/index",
    component: { template: "#tem" },
    redirect: "/index/product/1",
    children: [
        { path: "product/:id", component: { template: "#product" } },
        { path: "photo", component: { template: "#photo" } }
    ]
}

子路由是在router-view中嵌套了另一个router-view且它需要注册到路由对象里某个路由匹配规则中的children属性中,通过点击按钮或超链接可以让父路由所包含的子路由显示出来且不会把父路由组件给切换掉。

关于路由的总结

通常情况下,一个页面上只能有一个router-view,但可以有多个router-link,无论在同一个页面上的哪一个router-link发起了路由请求、待路由匹配成功后都是将对应的路由组件插入到这个页面上的那个唯一的router-view容器中。

路由组件和普通组件的结合使用

经典的top、left、right的css布局中把页面分成了顶部、侧边栏和内容区域,如果用路由来实现,那么当访问根页面的时候就需要render一个普通组件(index.vue)到index.html中,index.vue中把top直接做成一个固定的顶部banner,侧边栏则可以使用普通组件(left.vue)作为index.vue组件的普通子组件插入,然后右边的内容区域(content)则通过left.vue的router-link的点击发起路由请求进行切换不同的内容。由于在index页面上所有的路由链接发起的请求都是将对应的路由组件加载到同一个router-view(右边content区域),这就符合一个页面上只能有一个router-view的定义。如果你把left区域做成一个路由组件,那么index.vue中就会出现两个router-view,这样就违背了一个页面上只能有一个router-view的原则,这两个router-view(即侧边栏和右边内容区域)由于它们各自都代表了一个路由请求,而一个浏览器地址栏却只能发起一个路由请求,不可能同时发起两个路由请求,所以很多时候我们可能都需要用路由组件去结合普通组件达到目的。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>   
</head>
<body>
    <div class="box"></div>
</body>
</html>
<script src="/bundle.js"></script>

index.vue

将侧边栏注册为index.vue的普通子组件

<template>
    <div class="index-box">
        <div class="header-box"></div>
        <div class="bottom-box">
            <left></left>    
            <router-view></router-view>
        </div>
    </div>
</template>
<script>
    import left from "./left.vue";

    export default {
        components: {
            left: left           
        }
    }
</script>

right1.vue

<template>
    <div class="right-box">
        <h1>卡俄斯</h1>
    </div>
</template>
<script>
    export default { }
</script>

right2.vue

<template>
    <div class="right-box">
        <h1>普罗米修斯</h1>
    </div>
</template>
<script>
    export default { }
</script>

main.js

main.js将index.vue渲染到index.html

import Vue from "vue";
import "./css/style.css";
import router from "./js/router";
import index from "./components/index.vue";

var vm = new Vue({
    el: ".box",    
    router: router,
    render: (c) => { return c(index); } //注意render方法并不会通过路由请求得到index.vue,而是直接渲染了index.vue组件到index.html
});

router模板

import Vue from "vue";
import VueRouter from "vue-router";
import right1 from "../components/right1.vue";
import right2 from "../components/right2.vue";

Vue.use(VueRouter);

const router = new VueRouter({  
    routes: [
        { path: "/", redirect:"/index/right1" },
        { path: "/index/right1", component: right1 },
        { path: "/index/right2", component: right2 }
    ]
});
export default router;

路由组件组

一个页面只能有一个唯一的router-view,如果想实现一个路由请求能渲染多个路由组件,则可以为router-view指定name属性,然后在路由模板里使用components(注意是复数)指定多个路由组件匹配同一个路由请求。这样过程是:客户端发起路由请求,路由对象开始匹配这个路由地址,它首先匹配浏览器的路由地址,然后进入匹配成功的路由模板,接着发现有components路由组件组的定义,它会根据conponents中定义的路由匹配名称找到对应的多个路由组件一并返回给客户端,也就是说router-view一旦定义了name,那么整个路由匹配就会先匹配浏览器的路由地址,成功后再匹配components里的路由组件,最后再返回给客户端。所以,路由组件组的意思就是匹配一个路由地址返回多个路由组件。

<div id="box">
    <router-view></router-view>  //没有指定name属性的router-view在路由匹配成功后会把对应的组件插入这个路由组件
    <router-view name="left" class="left"></router-view> //指定name属性,让路由对象在components中查找对应的路由组件
    <router-view name="right" class="right"></router-view>
</div>

<script>
    var header = {
        template:"<h5>header</h5>"
    }

    var left = {
        template: "<h5>left</h5>"
    }

    var right = {
        template: "<h5>right</h5>"
    }

    var router = new VueRouter({
        routes: [
            {
                path: "/", components: { //当路由请求的是根目录时,路由匹配成功后不再返回某个单一的组件,而是返回多个由components指定的且与router-view的name相匹配的路由组件
                    default: header, //default默认返回header组件
                    left: left, //自定义指向left组件
                    right: right //自定义指向right组件
                }
            },
        ]
    });

    var vm = new Vue({
        el: "#box",
        data: {
            msg:"hello"
        },
        router:router
    });
</script>

子路由组件、子路由组件组的结合使用

但以上写法无法切换右边内容区域,考虑改造,参考如下代码来深入理解路由组件的嵌套规则,先看下图

图片展示了路由组件嵌套后的效果,整个页面分为top和bottom,top是header元素,它是固定的一个div。bottom是一个路由组件,它匹配对根目录的路由请求。bottom分为侧边栏和右边内容区域,侧边栏是一个普通的组件,将它注册为bottom路由组件的子组件,当页面一加载就会显示header和bottom,由于侧边栏不是路由组件,所以它也会随同bottom路由组件一起显示出来。接下来就是右边内容区域,很明显它是一个随着导航链接进行切换的路由组件,所以可以在bottom路由组件里定义left侧边栏和一个右边内容区域的router-view,右边内容区域是属于嵌套在bottom里的子路由组件,所以再路由匹配中还需要使用children属性来指定。现在思考一下,当点击register后(看上图),右边内容区域并不是只显示一个路由组件,而是显示了两个,一个是register1,另一个则是register2,这就需要两个router-view才行,其中一个不需要设置name,将它用来展示默认的email和register1两个路由组件,它们可以随着email和register两个超链接的点击而自动切换,而剩下一个register2怎么办呢?可以把它放在默认的router-view的后面,给它指定一个name,由于register1和register2隶属于一个相同的路由地址,所以我们可以在路由模板中设置components对它们进行匹配。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>   
    <style>
    </style>
</head>
<body>
    <div class="box">
        <div class="header-box"></div>
        <router-view></router-view> //用于显示bottom路由组件
    </div>
</body>
</html>
<script src="/bundle.js"></script>

main.js

import Vue from "vue";
import router from "./js/router";

var vm = new Vue({
    el: ".box",    
    router: router   
});

bottom.vue

<template>
    <div class="bottom-box">
        <left class="left-box"></left>
        <div class="right-box">
            <router-view></router-view> //email、register1路由组件会插入这个容器
            <router-view name="register"></router-view> //register2路由组件会插入这个容器
        </div>
    </div>
</template>
<script>
    import left from "../components/left.vue";
    export default {
        components: {
            left: left
        }
    }
</script>

left.vue

left作为bottom路由组件的普通子组件

<template>
    <div class="left-box">
        <ul>
            <li><router-link to="/index/email">email</router-link></li>
            <li><router-link to="/index/register">register</router-link></li>
        </ul>
    </div>
</template>
<script>
    export default { }
</script>

email.vue

bottom的子路由组件email.vue会根据路由请求显示在bottom路由组件里默认的router-view里边

<template>
    <div class="right-content0">
        <h1>email</h1>
    </div>
</template>
<script>
    export default { }
</script>

register1.vue

bottom的子路由组件register1.vue会根据路由请求显示在bottom路由组件里默认的router-view里边

<template>
    <div class="right-content1">
        <h1>register1</h1>
    </div>
</template>
<script>
    export default {}
</script>

register2.vue

bottom的子路由组件register2.vue会根据路由请求显示在bottom路由组件里命名的router-view里边

<template>
    <div class="right-content2">
        <h1>register2</h1>
    </div>
</template>
<script>
    export default {}
</script>

router模板

import Vue from "vue";
import VueRouter from "vue-router";
import bottom from "../components/bottom.vue";
import email from "../components/email.vue";
import register1 from "../components/register1.vue";
import register2 from "../components/register2.vue";

Vue.use(VueRouter);

const router = new VueRouter({  
    routes: [
        {
            path: "/",
            component: bottom, //路由根请求返回bottom组件插入到index.html的router-view里面
            redirect:"/index/email",
            children: [
                { path: "/index/email", component: email }, //右边内容区域默认显示email组件
                {
                    path: "/index/register", //请求这个路由时返回两个子路由组件
                    components: {
                        default: register1, //default:插入未命名的router-view中
                        register: register2  //插入命名的router-view中
                    }
                }
            ]
        }
    ]
});
export default router;
路由组件的动画
与组件动画是一样的设置方式,但唯一不同点是不需要一个布尔值来控制显示与隐藏,这个工作路是对象自动根据匹配的路由显示相应的组件而隐藏了不需要的组件。
<transition mode="out-in">
        <router-view></router-view> 
</transition>
.v-enter,.v-leave-to{
    opacity:0;
    transform:translateX(150px);
}

.v-enter-active, .v-leave-active {
    transition:all 0.5s ease;
}

Javascript - 学习总目录

Javascript - Vue - 路由的更多相关文章

  1. Javascript - Vue - webpack中的组件、路由和动画

    引入vue.js 1.cnpm i vue -S 2.在mian.js中引入vue文件 import Vue from "vue"//在main.js中使用这种方式引用vue文件时 ...

  2. vue路由原理剖析

    单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面, 实现这一点主要是两种方式: 1.Hash: 通过改变hash值 2.History: 利用history对象新特性(详情可出门左拐见:  ...

  3. 14.vue路由&脚手架

    一.vue路由:https://router.vuejs.org/zh/ 1.定义 let router = new VueRouter({ mode:"history/hash" ...

  4. 初印象至Vue路由

    初印象系列为快速了解一门技术的内容,后续会推出本人应用这门技术时发现的一些认识. Vue路由和传统路由的区别: Vue路由主要是用来实现单页面应用内各个组件之间的切换,同样支持传递参数等功能.而传统路 ...

  5. Vue路由开启keep-alive时的注意点

    Vue路由开启keep-alive时的注意点   这个不是业务的要求,但是看到每次进入页面就重新渲染DOM然后再获取数据更新DOM,觉得作为一个前端工程师有必要优化下的加载逻辑,正好vue提供了 ke ...

  6. Vue.js—组件快速入门及Vue路由实例应用

    上次我们学习了Vue.js的基础,并且通过综合的小实例进一步的熟悉了Vue.js的基础应用.今天我们就继续讲讲Vue.js的组件,更加深入的了解Vue,js的使用.首先我们先了解一下什么是Vue.js ...

  7. Vue 路由&组件懒加载(按需加载)

    当打包构建应用时,Javascript 包会变得非常大,影响页面加载速度.使用Vue路由懒加载和组件懒加载可以提升页面加载速度,减少白屏时间,提升用户体验. 用法有如下三种:(路由懒加载与组件懒加载用 ...

  8. Vue路由Hash模式分析

    Vue路由Hash模式分析 Vue-router是Vue的核心组件,主要是作为Vue的路由管理器,Vue-router默认hash模式,即使用URL的Hash来模拟一个完整的URL,当URL改变时页面 ...

  9. Javascript - Vue - vuex

    vuex 这是一个与vue配套的公共数据管理工具,可以将一些需要共享的数据保存到vuex中,以此方便项目中的任何组件都可以从vuex中得到共享数据.cnpm i vuex -S 装包 读取数据 //在 ...

随机推荐

  1. SpringBoot | 3.1 配置数据源

    目录 前言 1. 数据源的自动配置 2. *数据源自动配置源码分析 2.1 DataSourceAutoConfiguration:数据源自动配置类 2.2 JdbcTemplateAutoConfi ...

  2. 剖根问底:Java 不能实现真正泛型的原因是什么?

    大家好,我是二哥呀! 今天我来给大家讲一下,Java 不能实现真正泛型的原因是什么? 本文已同步至 GitHub <教妹学 Java>专栏,风趣幽默,通俗易懂,对 Java 初学者亲切友善 ...

  3. PHP imap 远程命令执行漏洞(CVE-2018-19518)

    影响版本 PHP:5.6.38 系统:Debian/ubuntu 构造数据包 成功执行命令echo '1234567890'>/tmp/test0001

  4. Hadoop 3.1.1 - Yarn 服务 - 总览

    YARN 服务 总览 Yarn 服务框架为在 Yarn 原生环境里长时间运行的服务,提供了一流的支持和接口.简言之,它扮演了容器编排系统的角色,统一管理 Yarn 上运行的容器化服务.它同时支持 Do ...

  5. QT从入门到入土(四)——多线程(QtConcurrent::run())

    引言 在前面对Qt多线程(QThread)做了详细的分析:QT从入门到入土(四)--多线程(QThread) - 唯有自己强大 - 博客园 (cnblogs.com) 但是最近在做项目时候,要将一个函 ...

  6. 什么是软件的CLI安装

    Websoft9 在进行开源软件的集成与自动化安装研究过程中发现有些软件有CLI安装模式,例如Gitlab CLI版本.Ghost CLI.PHP CLI等,CLI安装是什么意思? CLI(Comma ...

  7. openssl查看证书命令

    openssl x509部分命令打印出证书的内容:openssl x509 -in cert.pem -noout -text打印出证书的系列号openssl x509 -in cert.pem -n ...

  8. 如何实现让div垂直居中,左右10px,高度始终为宽度一半

    方法一:利用height:0; padding-bottom: 50%; <!DOCTYPE html><html lang="en"> <head& ...

  9. UVa120 煎饼(选择排序思想)

    题目背景 给你一迭薄煎饼,请你写一个程式来指出要如何安排才能使这些薄煎饼由上到下依薄煎饼的半径由小到大排好.所有的薄煎饼半径均不相同. 要把薄煎饼排好序需要对这些薄煎饼做翻面(flip)的动作.方法是 ...

  10. 二、Windows安装与简单使用MinIO

    MinIO的官方网站非常详细,以下只是本人学习过程的整理 一.MinIO的基本概念 二.Windows安装与简单使用MinIO 三.Linux部署MinIO分布式集群 四.C#简单操作MinIO 一. ...