当前位置:   article > 正文

Vue 单页、路由_vue单页面路由的实现方式

vue单页面路由的实现方式


 

单页应用:一个页面即一个简单应用,组件化开发

传统的页面调转是浏览器请求新页面,单页是把原本的多个页面以组件的形式集成在一个页面中,页面跳转时由vue路由到目标页面,因为目标页面是当前页面的一部分,切换到指定部分即可,浏览器不用发起新请求。
 

单页、路由的基本使用

#下载vue的路由插件
npm install vue-router
  • 1
  • 2
<div id="app"></div>

<!-- 引入vue.js -->
<script src="js/vue.js"></script> 

<!-- 引入vue的路由插件。上线时均要换为min版 -->
<script src="js/vue-router.js"></script>

<script>
    // 首页
    var Index={
        template:`
            <div>
                <p>this is the index page</p>
                <p><a href="#/login">login</a></p>   <!-- 注意url写法,#/开头 -->
                <p><a href="#/register">register</a></p>
            </div>
        `,
    }
    

    // 登录页面
    var Login={
        template:`
            <div>
                <p>this is the login page</p>
                <p><a href="#/index">index</a></p>
                <p><a href="#/register">register</a></p>
            </div>
        `
    }
    

    // 注册页面
    var Register={
        template:`
            <div>
                <p>this is the register page</p>
                <p><a href="#/index">index</a></p>
                <p><a href="#/login">login</a></p>
            </div>
        `
    }


    // 启用vue路由
    Vue.use(VueRouter);
    

    // 创建路由对象
    var router=new VueRouter({  //参数是对象
        routes:[  //配置路由规则,对象数组形式
            {path:'',name:'index',component:Index},  //path指定映射地址,注意不带#,component指定组件。path=""表示该页面组件是默认显示的页面
            {path:'/login',name:'login',component:Login},
            {path:'/register',name:'register',component:Register},
        ]
    });

    
    new Vue({
        el: '#app',
        router: router,  //设置路由对象。因为我们使用的路由对象和key名称相同,也可以像html属性一样简写为一个:router
        template:`
            <div>
                <!--路由页面只是当前页面的一部分,当前页面可以写一些其他内容,写的内容是所有路由页面-->
                <p>this is common area</p>  <!-- 公共部分,页面都有的部分 -->
                <router-view></router-view>  <!-- 目标页面。路由到哪个页面,就用对应的组件替换此元素 -->
            </div>
        `,
    })
</script>   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

运行,假设这个html页面的地址是:xxx.html#/
则首页的地址是:xxx.html#/
登录页面的地址是:xxx.html#/login
注册页面的地址是:xxx.html#/register

表面上是3个页面,但实际上只有xxx.html一个页面,这3个页面都在xxx.html中。<router-view>是一个容器,用来容纳目标页面。
 

一个组件即一个页面,组件往往很大,通常把每个组件写在单独的js文件中,在xxx.html中使用<script src=“”>引入

 

路由模式

有2种路由模式

1、hash模式(默认)
原理:监听地址栏url的 hashchange 事件,url改变时获取新url的哈希值,与VueRouter对象中配置的路由规则比较,找到新url对应的组件,用对应的组件替换<router-view>。

特点

  • url中含有哈希字符 #
  • 进行路由跳转时直接本地跳转,不会请求服务器
  • 正因为第二点(本地路由),SEO效果差
     

2、history模式(推荐)

  • url正常、好看一些,示例:https://example.com/user/id
  • 进行路由跳转时会请求服务器,SEO效果比hash模式好
  • 正因为第二点,每次路由都会向服务器请求目标url资源,而单页应用打包后html文件只有一个 index.html,https://example.com/user/id 之类目标url对应的静态资源实际并不存在,会报404,需要在nginx之类的服务器上配置一下,把这个单页应用的路由请求都打到 index.html 上,让单页应用内部自行进行路由。

参考:https://router.vuejs.org/zh/guide/essentials/history-mode.html

 

路由跳转

实现路由跳转有3种方式

  • <a>链接
  • <router-link>标签
  • $router对象
<a href="#/login">login</a>  <!-- 要带# -->

<router-link to="/login">login</router-link>  <!-- 不带# -->

<script>
    new Vue({
        el: "#app",
        router,
        template: `
            <div>
                <button @click="goLogin">login</button>
                <router-view></router-view> 
            </div>
        `,
        methods: {
            goLogin() {
                this.$router.push({ path: "/login" });  //不带#
            },
        },
    });
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

<router-link>、$router都是vue路由中的,都用路由了,url中会自动加#号,我们写路径的时候不需要加#号。

<a>是html的标签,url中不会自动加#号,需要我们自己加#号。
 

$router常用的方法

  • push()  跳转到指定页面,会往history中插入记录
  • replace()  和push()差不多,只是不会往history中插入记录
  • go(-1)  跳转到history中的上一条记录,相当于点击浏览器的后退箭头
  • forward(1)  跳转到history中的下一条记录,相当于点击浏览器的前进箭头

$router有个兄弟对象$route,$route常用的属性:path、query、params
 

在html中,<router-link>用得多;在js代码中,用$router

 

路由传参

1、<a>链接方式

<a href="#/xxx?username=chy&age=20">index</a>  <!-- 传参 -->

<script>
    // 页面组件
    var Xxx={
        template:`
            <div>
                <p>{{this.$route.query.username}}  {{this.$route.query.age}}</p>
                <p>{{username}} {{age}}</p>
            </div>
        `,
        data(){
            return{
                username:'',
                age:''
            }
        },
        created(){  //路由到此组件|页面时,会新建此组件的实例,只能在created()中获取传递的数据
            this.username=this.$route.query.username;  //query是查询字符串对象,<a>链接传递的参数只能用query来取
            this.age=this.$route.query.age;
        }
    }
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

如果只在创建组件时使用一次,直接用组件的$route.query取值即可;如果后续还要使用,则需要用变量来保存参数

 

2、<router-link>、$router对象方式

都可以用query或者params传递参数

<!-- query,get请求 -->
<router-link :to="{name:'xxx',query:{username:'chy',age:20}}">xxx</router-link>  

<!-- params,post请求 -->
<router-link :to="{name:'xxx',params:{username:'chy',age:20}}">xxx</router-link> 
  • 1
  • 2
  • 3
  • 4
  • 5
// $router对象方式,query、params
this.$router.push({name:'xxx', query:{username:'chy',age:20}});
this.$router.push({name:'xxx', params:{username:'chy',age:20}});
  • 1
  • 2
  • 3

路由传参指定目标view时,不要用 path 指定路径,使用path取不到 query、params 传递的参数,换成使用 name 指定名称。

取值方式和<a>差不多,$route.query、$route.params,什么方式传就用什么方式取

 
常使用ES6的解构赋值处理参数

let {username,password} = req.query;
  • 1

 

3、path动态参数方式

var router = new VueRouter({
    routes: [
    	//path 参数名前面加冒号,name指定组件名
        {path: "/xxx/:username", name: "xxx", component: Xxx},  
    ],
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//可以用 name + params 传递参数,url中参数放在 params中
this.$router.push({name:'xxx', params:{username:'xxx'}});

//如果要传递的值是某个变量的值,可以用path传递,直接拼接在path中
this.$router.push({path: '/xxx/' + user.username, params: {}});
  • 1
  • 2
  • 3
  • 4
  • 5

不管用哪种方式,本质都是用整个params作为map传递url中所需的全部参数,params已经被占用了,无法再使用params传递其它参数,但依然可以用query传递参数。
 

//在在目标组件中都是通过 $route.params 获取url传递的参数
this.$route.params.username

//this可缺省
$route.params.username
  • 1
  • 2
  • 3
  • 4
  • 5

 

路由传参 参数不刷新的问题

以上传参方式都存在一个问题:多次传参,如果直接使用参数,可以获取到本次的参数;如果先把参数赋给变量,使用变量,则变量的值永远是第一次传递的参数值,即参数不刷新。
 
原因:把变量赋值写在created()中,这个钩子函数只在组件创建时执行1次,vue路由会复用组件,后续再向该组件传递参数时,不会调用重新创建该组件,也就不会执行created()重新赋值,这个问题在复用组件时经常遇到。
 
如果参数只在页面加载时读取一次,可以在create()中直接取,后续还要使用这个值的话,可以用变量来保存;如果要多次获取不同的路由参数,后续的路由参数不会刷新,如何解决参数不刷新问题?2种方案
 

1、使用 :key 标识路由跳转

<router-view :key="$route.fullPath"></router-view> 
  • 1

fullPath是完整的url,如果是query方式传参,fullPath中包含了参数;如果是params方式传参,参数写成restful风格(用一个唯一标识参数表的字段,比如username、uid),fullPath中也包含了参数。
 
参数不同时 => $route.fullPath不同 => key不同,key不同时会重新创建组件,执行created()重新获取参数给变量赋值。
 
核心思路是:参数不同时key也要不同,key不同就会重新创建组件。key不一定要用$route.fullPath,常用的还有

$route.query|params.username|uid  //能唯一标识参数表的参数  
new Date().getTime()  //时间戳(毫秒级)
  • 1
  • 2

此种方式,参数不同时会重新创建组件,往往会造成组件的频繁创建、销毁,开销很大,不建议使用。

 

2、使用数据监听(推荐)

在目标组件中监听$route.query或者$route.params,在数据监听中进行赋值,不需要使用created()

watch:{  //监听$route.query|params,当然直接监听$route也行
    '$route.params'(){ //有.号,要引起来,不然识别不了
        this.username=this.$route.params.username;  //参数变化时就重新获取参数
        this.age=this.$route.params.age;
    }
},    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

路由到同一个页面时会复用组件,不重新创建组件,开销小,推荐。

最好是抽象出一个处理参数的方法,初次路由到该页面时在create()中调用1次,后续再次路由到该页面时watch中调用。需要注意监听的是$route.query|params,只要其中某个参数有变化,就会触发事件。

组件复用时经常用这种方式来获取最新的参数

 

嵌套路由

路由配置中嵌套其它的路由配置

<div id="app"></div>

<script>
    // 导航
    var Nav={
        template:`
            <div>
                <router-link :to="{name:'blog.index'}">首页</router-link>
                <router-link :to="{name:'blog.article'}">文章</router-link>
                <router-link :to="{name:'blog.idea'}">想法</router-link>
                <router-link :to="{name:'blog.message'}">留言</router-link>

                <router-view></router-view>  <!-- 留坑,点击上面4个路由链接,会在此处显示对应的页面 -->
            </div>
        `,
    }
    

    // 首页
    var Index={
        template:`
            <div>
                <p>这是首页部分</p>
            </div>
        `,
    }
    

    // 文章
    var Article={
        template:`
            <div>
                <p>这是文章部分</p>
            </div>
        `,
    }
    

    // 想法
    var Idea={
        template:`
            <div>
                <p>这是想法部分</p>
            </div>
        `,
    }


    // 留言
    var Message={
        template:`
            <div>
                <p>这是留言部分</p>
            </div>
        `,
    }


    // 启用路由
    Vue.use(VueRouter);


    // 创建路由对象
    var router=new VueRouter({
        routes:[ 
            {path:'/',name:'blog',component:Nav,children:[   //path直接映射到根路径(当前html页面下)下,children设置要嵌套的路由
                {path:'',name:'blog.index',component:Index},  //默认页面
                {path:'/article',name:'blog.article',component:Article},  //嵌套路由的name一般要带上外部的路由容器,一看就知道关系
                {path:'/idea',name:'blog.idea',component:Idea},
                {path:'/message',name:'blog.message',component:Message},
            ]},
        ]
    });

        
    new Vue({
        el:'#app',
        router,  //使用路由
        template:`
            <div>
                <router-view></router-view>  <!-- 留给nav的坑位 -->
            </div>
        `,
    })

</script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

 
嵌套路由的path可以映射到根路径下,也可以使用相对路径,相对于外部路由

{path:'/blog',name:'blog',component:Nav,children:[   //xxx.html#/blog
    {path:'',name:'blog.index',component:Index},  //默认页面
    {path:'/article',name:'blog.article',component:Article},  // /开头是映射到根路径下,xxx.html#/article
    {path:'idea',name:'blog.idea',component:Idea},  // 相对于外部路由,xxx.html#/blog/idea
    {path:'message',name:'blog.message',component:Message},
]},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

 

路由守卫

一个页面路由到另一个页面,路由到目标页面之前可以用路由守卫做一些处理,比如登录检测、权限检查,不满足就给出提示信息,不路由到目标页面。

现在的项目基本都是mvc模式,登录检测、权限检查等请求预处理在后台已经做了,前端没必要用路由守卫,此处简单提一下

//写在html(单页容器)的Vue对象的mounted()中
mounted(){
    router.beforeEach( (to,from)=>{   //路由守卫,校验每一个路由跳转。此处使用es6的箭头函数,参数:目标页面、来源页面
        //......
    });
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/262496
推荐阅读
相关标签
  

闽ICP备14008679号