赞
踩
单页应用:一个页面即一个简单应用,组件化开发
传统的页面调转是浏览器请求新页面,单页是把原本的多个页面以组件的形式集成在一个页面中,页面跳转时由vue路由到目标页面,因为目标页面是当前页面的一部分,切换到指定部分即可,浏览器不用发起新请求。
#下载vue的路由插件
npm install vue-router
<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>
运行,假设这个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>。
特点
2、history模式(推荐)
参考:https://router.vuejs.org/zh/guide/essentials/history-mode.html
实现路由跳转有3种方式
<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>
<router-link>、$router都是vue路由中的,都用路由了,url中会自动加#号,我们写路径的时候不需要加#号。
<a>是html的标签,url中不会自动加#号,需要我们自己加#号。
$router常用的方法
$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>
如果只在创建组件时使用一次,直接用组件的$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>
// $router对象方式,query、params
this.$router.push({name:'xxx', query:{username:'chy',age:20}});
this.$router.push({name:'xxx', params:{username:'chy',age:20}});
路由传参指定目标view时,不要用 path 指定路径,使用path取不到 query、params 传递的参数,换成使用 name 指定名称。
取值方式和<a>差不多,$route.query、$route.params,什么方式传就用什么方式取
常使用ES6的解构赋值处理参数
let {username,password} = req.query;
3、path动态参数方式
var router = new VueRouter({
routes: [
//path 参数名前面加冒号,name指定组件名
{path: "/xxx/:username", name: "xxx", component: Xxx},
],
});
//可以用 name + params 传递参数,url中参数放在 params中
this.$router.push({name:'xxx', params:{username:'xxx'}});
//如果要传递的值是某个变量的值,可以用path传递,直接拼接在path中
this.$router.push({path: '/xxx/' + user.username, params: {}});
不管用哪种方式,本质都是用整个params作为map传递url中所需的全部参数,params已经被占用了,无法再使用params传递其它参数,但依然可以用query传递参数。
//在在目标组件中都是通过 $route.params 获取url传递的参数
this.$route.params.username
//this可缺省
$route.params.username
以上传参方式都存在一个问题:多次传参,如果直接使用参数,可以获取到本次的参数;如果先把参数赋给变量,使用变量,则变量的值永远是第一次传递的参数值,即参数不刷新。
原因:把变量赋值写在created()中,这个钩子函数只在组件创建时执行1次,vue路由会复用组件,后续再向该组件传递参数时,不会调用重新创建该组件,也就不会执行created()重新赋值,这个问题在复用组件时经常遇到。
如果参数只在页面加载时读取一次,可以在create()中直接取,后续还要使用这个值的话,可以用变量来保存;如果要多次获取不同的路由参数,后续的路由参数不会刷新,如何解决参数不刷新问题?2种方案
1、使用 :key 标识路由跳转
<router-view :key="$route.fullPath"></router-view>
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() //时间戳(毫秒级)
此种方式,参数不同时会重新创建组件,往往会造成组件的频繁创建、销毁,开销很大,不建议使用。
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;
}
},
路由到同一个页面时会复用组件,不重新创建组件,开销小,推荐。
最好是抽象出一个处理参数的方法,初次路由到该页面时在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>
嵌套路由的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},
]},
一个页面路由到另一个页面,路由到目标页面之前可以用路由守卫做一些处理,比如登录检测、权限检查,不满足就给出提示信息,不路由到目标页面。
现在的项目基本都是mvc模式,登录检测、权限检查等请求预处理在后台已经做了,前端没必要用路由守卫,此处简单提一下
//写在html(单页容器)的Vue对象的mounted()中
mounted(){
router.beforeEach( (to,from)=>{ //路由守卫,校验每一个路由跳转。此处使用es6的箭头函数,参数:目标页面、来源页面
//......
});
},
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。