目录
Vue路由
用的前端路由系统,通过改变URL,在不重新请求页面的情况下,更新页面视图。
利用URL中的hash(“#”);
vue 中路由的跳转方式:
1. 声明式路由 : 通过 router-link 标签实现的
2. 编程式路由 : 通过 路由对象的方法 $router.push() 方法实现的
路由加前缀
new Router({
mode: 'history', // 访问路径不带#号
base: '/page/aa', // 配置单页应用的基路径
});
页面这样访问 http://localhost:8080/page/aa/ 和 http://localhost:8080/ 访问的效果是一样的。
声明式路由
<style>
.router-link-exact-active {
color: red;
/* 渲染的属性 */
}
</style>
<body>
<div id="app">
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<p>
<router-link to='/'>首页</router-link>
<!--router-link-active :当前激活的路由 因为/,其它路由也有/, 所以会一直被激活 -->
<router-link to='/main'>主体</router-link>
<router-link to='/login'>登录</router-link>
</p>
<!-- 5 router-view标签是vue提供的内置标签,专门用来渲染 路由 -->
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
// 1. 创建路由页面模板 本质就是组件
const main = {
template: `<div>这是主体页面</div>`
}
const login = {
template: `<div>这是登录页面</div>`
}
const index = {
template: `<div>这是首页默认路由</div>`
}
// 2. 创建路由的配置项
const routes = [{
path: '/', // 路径匹配的路由
component: index
}, {
path: '/main', // 路径 匹配的路由
// 路由级页面组件 component注册组件
component: main
}, {
path: '/login',
component: login
}]
// 3. 生成路由的实例对象
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 把路由对象注册到vue 实例中
const app = new Vue({
el: "#app",
// 路由的配置项
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
router
})
</script>
router-link 的 tag 属性 可以指定渲染的标签 tag属性值是标签名
指定类名: 给router-link标签添加 属性指定类名
active-class: 默认值 router-link-active(激活)
exact-active-class: 默认值 router-link-exact-active(渲染)
例子
<router-link to='/' tag='p' active-class='active' exact-active-class='current'>首页</router-link>
编程式路由
路由传参:
1. 通过query实现 : query 传参 和 path 结合使用
2. 通过params实现 : parmas 传参 和 name 结合使用 (name 就是命名路由的一个属性, 通过name属性命名路由)
3. path 结合 params 使用, 则params会被忽略
query结合path传参结合使用方式通过 query 传递参数 : query 是一个对象; 传递的参数会拼接在路径上url
<div id="app">
<!-- <router-link to='/list'>列表</router-link>
<router-link to='/order'>订单</router-link> 这是 声明式路由的写法-->
<!-- 编程式路由的写法 -->
<!--(1) 通过query实现 传参 -->
<button @click='list'>列表</button>
<router-view></router-view>
</div>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
const List = {
template: `
<div>
hello 列表
</div>
`
}
const routes = [{
path: '/list',
component: List
}]
const router = new VueRouter({
routes
})
const app = new Vue({
el: '#app',
router,
methods: {
list() {
// (1)编程式路由: 通过 路由对象$router 的 push() 进行跳转
//this.$router.push('list') //这样写是跳转 参数是一个字符串类型的path
// (1) 跳转和传参 参数是一个对象 可以进行路由传参
this.$router.push({
path: '/list',
// 通过query进行传参 第一个种传参形式通过 query, 参数会拼接在路径的后边 , 类似于get请求
//query 传参 页面刷新 参数不会丢失
query: {
tab: 'share',
id: 100
},
// 如果 使用了path 进行路由跳转,添加params 则会被忽略
// params: {
// id: 100
// }
})
}
}
})
</script>
</body>
上面是在编程式路由中传参
声明式路由传参
也可以在<router-link : to=>中传参
这时的to前面要加v-bind,来告诉vue这是一个对象
<router-link :to='{
path:"/order",
query:{
id:100,
tab: "share",
}
}'>订单</router-link>
params结合name传参使用方式 params 也是一个对象 ; 传递的参数是不会显示在路径URL 上
<div id="app">
<!-- <router-link to='/list'>列表</router-link>
<router-link to='/order'>订单</router-link> 声明式路由 -->
//编程式路由
<button @click='order'>订单</button>
<router-view></router-view>
</div>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
const Order = {
template: `
<div>
order 页面
</div>
`
}
const routes = [{
path: '/order',
// name 命名路由,可以给路由起别名
name: 'Order',
component: Order
}]
const router = new VueRouter({
routes
})
const app = new Vue({
el: '#app',
router,
methods: {
order() {
//(2)编程式路由: 通过 路由对象$router 的 push() 进行跳转
// this.$router.push('order')
//(2)传参和跳转 路由传参的方式:通过 params 传参,需要结合命名路由实现
// params 传参 页面刷新,参数就会自动丢失 !!
this.$router.push({
name: 'Order', //这个name名与路由途径routes中name名对应
params: {
type: '衣服'
}
// query 可以 和name结合使用,但是不建议(使用后刷新参数不丢失)
// query: {
// id: 200
// }
})
}
}
})
</script>
对比
路由传参:
1. query 传参 : {path:'/zoom', query:{}}
2. params 传参 : {name:'zoom', params:{}}
动态路由
动态路由渲染的是同一个模板
获取声明式动态路由的参数:
组件模板中: $route.params.id
方法中: this.$route.parmas.id
获取编程式动态路由的参数:
1. 获取query参数:
组件模板中获取: $route.query.key
方法中(组件中): this.$route.query.key
2. 获取params参数:
组件模板中获取: $route.params.key
方法中(组件中): this.$route.parmas.key
vuecli实例
<!--组件中使用 <p>传过来的=>:{{ $route.params.type }}</p> -->
<p>传过来的=>{{ listID }}</p>
----
computed: {//计算属性
listID() {
// params是参数的意思
return this.$route.params.type;
},
},
区分两个对象:
$route : 代表的是当前路由信息对象 (就是url地址的实时参数)
$router : 代表的是路由实例对象
vue路由的通配符
path:'*',//匹配任意路径
例如 path:"/box*"
这个时候跳转的路径里只要含有 box 就可以跳转
可以是/box1或/box&token=123
例如 path: '/box/:id(\\d+)',
只要/box/2 后面是数字就跳转
watch监听路由
方法一:
watch:{
$router(to,from){
console.log(to.path)
}
}
方法二:
watch: {
$route: {
handler: function (val, oldVal){
console.log(val);
},
// 深度观察监听
deep: true
}
},
方法三:
watch: {
'$route' : 'getPath'
},
methods: {
getPath(){
console.log( this .$route.path);
}
}
监听的是data中的数据的改变, 监听的是 handler(newValue, oldValue)
监听的是路由的改变:监听的是 handler(to, from) 从哪个路由 跳转到哪个路由 (从哪来到哪去)
fullPath和path区别
fullPath匹配路由,path匹配路径。
例如:
路由是:/path/one
真正路径是:/path/true
那么此时path为/path/true,而fullPath为/path/one
router对象的方法
和BOM: history 对象 类似
router.replace() : 替换当前路由, 该路由不会添加到历史记录中
router.go(n) : 前进/后退 路由跳转 n:整数, 正值代表前进, 负值后退
router.back() : 后退
router.forward() : 前进
嵌套路由和重定向(redirect)
vue 路由: 存在子由路(嵌套路由) 通过 children 属性定义嵌套路由
使用嵌套路由时。 父路由和子路由的路径会自动进行拼接, 得到最后的路由 /parent/child
所以子路由的路径匹配不用写斜杠/
const routes = [
{
path:path,
component:parentname,
// children 就是子由路
children:[
{
path:path,
component:childname
},{
path:path,
component:childname
}
]
}
]
例:
const routes = [
{
path: '/',
name: 'Home',
component: Home,
redirect: '/about',当访问/时。重定向到/about
},
{
path: '/about',
name: 'about',
component: () => import('../views/About.vue')
}
]
<body>
<div id="app">
<router-link to='/index'>首页</router-link>
<router-link to='/order'>订单</router-link>
<router-view></router-view>
<!-- 出口 -->
</div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
const index = {
template: `
<div>
<p>这是首页</p>
<router-link to='/list'>二级页面</router-link>
<router-view></router-view>
</div>
`
//二级页面和出口
}
const order = {
template: `
<div>
<p>这是订单</p>
</div>
`
}
const list = { //二级页面的模板
template: `
<div> <strong>这是商品列表页 </strong></div>
`
}
const routes = [{
path: '/',
//页面重定向
redirect: '/index'
//要不然component: index再写一次
}, {
path: '/index',
component: index,
children: [{
path: '/list',
component: list
}]
}, {
path: '/order',
component: order
}]
const router = new VueRouter({
routes
})
const app = new Vue({
el: "#app",
router
})
</script>
导航守卫
导航守卫就是路由跳转过程中的一些钩子函数
组件内守卫和组件钩子函数不冲突
官方解释:
“导航”表示路由正在发生改变。正如其名,vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
简单的说,导航守卫就是路由跳转过程中的一些钩子函数。路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿,这就是导航守卫。类似于组件生命周期钩子函数
1. 全局守卫 : 全局守卫是路由对象的 router (路由的实例对象)
前置全局守卫 beforeEach 进入路由之前
全局解析守卫 beforeResolve 动态路由切换时会触发该守卫
全局后置守卫 afterEach 离开路由
2. 路由独享守卫 : 路由专享, 在路由的配置项中使用的一个属性
beforeEnter
3. 组件内守卫 : 组件专享, 在路由组件中添加的钩子函数
beforeRouteEnter 进入路由
beforeRouteUpdate (2.2 新增) 切换(更新)路由
beforeRouteLeave 离开路由
每个守卫都有三个参数:
to:这是你要跳去的路由对象。
from:这是你要离开的路由对象。
next:是一个方法,它接受参数。这个方法必须调用要不就跳不过去了,你可以把它看做保安。必须给它打个招呼,要不然不让你过。
next()。这就是告诉保安我要过去,去哪里呢? 就是to了。
next(false)。如果传入false。保安就不让过了。也就是中断跳转。
next({path:“/”})。这个意思是保安不让过,并把你交到另一地方审查了。也就是中断跳转,跳转到一个新的路径。
(1)
(2)
当进入到路由页面触发
beforeRouteUpdate 动态路由切换时会触发该守卫
将url中的地址清空或换一个地址,动态路由的切换不算离开路由
<body>
<div id="app">
<router-view></router-view>
</div>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
// 路由组件
const order = {
template: '<div>order 订单页</div>',
beforeRouteEnter(to, from, next) {
console.log('(3)组件内守卫 beforeRouteEnter 进入路由');
next()
},
// beforeRouteUpdate 动态路由切换时会触发该守卫
beforeRouteUpdate(to, from, next) {
console.log('(3)组件内守卫 beforeRouteUpdate 切换路由');
next()
},
beforeRouteLeave(to, from, next) {
console.log('(3)组件内守卫 beforeRouteLeave 离开路由');
next()
}
}
const list = {
template: '<div>list 列表页</div>'
}
// 路由配置
const routes = [{
path: '/order/:id',
component: order,
//路由独享守卫
beforeEnter: function(to, from, next) {
console.log('(2)路由独享守卫@@@@@@');
// console.log(to);
// console.log(from);
next()
}
}, {
path: '/list',
component: list
}]
const router = new VueRouter({
routes
})
// 1----前置全局守卫 所有的路由在匹配之前都会被拦截
// 接受参数: to(到哪去), from(从哪来), next(放行, 还可以进行重定向)
router.beforeEach((to, from, next) => {
// 放行
console.log(' 前置全局守卫 !!!');
// console.log(to);
// console.log(from);
next()
})
router.beforeResolve((to, from, next) => {
console.log(' 全局解析守卫 !!!');
next()
})
router.afterEach((to, from) => {
console.log(' 全局后置钩子!!! ');
})
const app = new Vue({
el: '#app',
router
})
</script>
</body>
前置全局守卫beforeEach:/及路由元信息
路由 元信息 meta 属性:
如果你想在路由中添加自定义的属性和信息,可以使用 meta 属性
路由对象的 matched 属性: 包含了所有的路由信息对象,(也包含元信息 meta 属性,父路由和子路由都包含)
示例:
{
path: '/home',
component: home,
meta: {
// 自定义的路由传递的信息
ticket: false //false就是不需要买票
}
}
一个路由匹配到的所有路由记录为 $route 对象(还有在导航守卫中的路由对象)的 $route.matched 数组。因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段。
to.matched.map(item => {
if (item.meta.ticket) {//判断自定义路由传递的信息
下步操作
}
to.matched.some()
if (to.matched.some(record => record.meta.属性) ),
如果对这类写法不熟悉,可以去看看es6的箭头函数,
这句话就是返回遍历的某个路由对象,我们定义为为record,检测这个对象是否拥有meta这个对象,
如果有meta这个对象,检测它的meta对象是不是有meta中属性,且为true,
router.beforeEach((to, from, next) => {
console.log(to);//to要去的地方
// 判断是否需要买票
if (to.matched.some(route => route.meta.ticket)) { //
// 判断是否有票
if (localStorage.getItem('ticket')) {//如果有票放行
next()
} else {
// next('/ticket')
next({
path: '/ticket',//如果没有票,跳转到买票页面,同时传参说明你是哪个地方来的
query: {
// from: to.path // from=%2Fzoom 传递的参数,格式不是我们想要的 ,下面去除%
from: to.path.substring(1)
}
})
}
} else {
next()
}
})
//买票页
const ticket = {
template: `
<div>
购票处
<button @click='buyTicket'>买票</button>
<router-link to='/home'>回家</router-link>
</div>
`,
methods: {
buyTicket() {
// 把票存储到本地
localStorage.setItem('ticket', "票")
// 买完票后可以进入目的地 获取路由参数
let from = this.$route.query.from
this.$router.push({
path: `/${from}`//买完票直接跳转进入到你来的地方
})
}
}
}