Vue Router路由

作者: pdnbplus | 发布时间: 2024/06/25 | 阅读量: 62

Vue Router路由--潘登同学的前端笔记

安装Vue Router

官方文档

<!-- 注意:要在cd vue-router-demo下 -->
cnpm install vue-router --save
<!-- 上面那个不行就用下面的 -->
npm install vue-router --save

save操作能将依赖写入package.json

然后增加路由配置(在src下main.js文件中)

import VueRouter from 'vue-router'

Vue.use(VueRouter)

启动

npm run serve

Router的基础使用

(均在main.js下进行操作)

  • 1.导入组件(页面)
import Home from "./pages/Home.vue"
import User from "./pages/User.vue"
  • 2.定义路由(pathkey表示跳转后页面link的显示)
const routes = [
  {path:"/",component:Home},
  {path:"/User",component:User},
]
  • 3.创建路由对象
const router = new VueRouter({
  routes
})
  • 4.挂载路由 将路由对象挂载到Vue的实例对象当中
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')
  • 5.最后回到APP.vue 在主容器下,定义路由出口
<router-view></router-view>
  • 6.导航效果(在APP.vue 在主容器下)

to属性与之前的path属性对应

<router-link to="/">Go to Home</router-link>
<router-link to="/User">Go to User</router-link>

动态匹配路由

(在user后面加上用户id不同用户不同页面信息)

  • 1.修改上面第二步
// useid是一个key不是固定写法,且传入参数没有限制
const routes = [
  {path:"/",component:Home},
  {path:"/User/:useid/:name",component:User},
]
  • 2.在跳转的页面传递值
<router-link to="/User/100001/Pandeng">Go to User</router-link>
  • 3.在对应的页面获取数据
<div>
    <h3>用户中心{{ $route.params.useid }}--{{ $route.params.name }}</h3>
</div>

文件分离

因为main.js是整个项目的主入口文件,所有东西都放进去不好;

在assets同级目录下,新建一个router文件夹,新建一个index.js

将路由相关的语句转到新文件中

import Vue from 'vue'
import VueRouter from 'vue-router'

import Home from "../pages/Home.vue"
import User from "../pages/User.vue"

Vue.use(VueRouter)
// 定义路由
// useid是一个key不是固定写法
const routes = [
    { path: "/", component: Home },
    { path: "/User/:useid/:name", component: User },
]

// 创建路由对象
const router = new VueRouter({
    routes,
})
// 挂载路由 导出路由
export default router

回到main.js中, 导入即可

import router from "./router"

// 挂载路由 将路由对象挂载到Vue的实例对象当中

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

路由嵌套

  • 1.在New.vue同级目录下创建新文件夹newsub
<!-- 创建新闻向下子目录页面(sports_new.vue,entertainment_new.vue) -->
<div>
    <h3>体育新闻</h3>
</div>

<div>
    <h3>娱乐新闻</h3>
</div>
  • 2.回到index.js文件中添加子页面
import Sports_new from "../pages/newsub/sports_new.vue"
import Entertainment_new from "../pages/newsub/entertainment_new.vue"

// 在New对象新增children的key

{ path: "/News", component: News,
    children:[
        {path: "Sports_new", component: Sports_new,},
        {path: "Entertainment_new", component: Entertainment_new,},
    ]},
  • 3.去到New.vue文件中,添加子目录
<div>
    <h3>新闻页面</h3>
    <router-link to="/News/Sports_new">Go to Sports</router-link> |
    <router-link to="/News/Entertainment_new">Go to Entertainment</router-link>
    <!-- 路由出口 -->
    <router-view></router-view>
</div>

编程式导航

前面的路由跳转,在页面时都会被渲染成a标签,如果我们想通过事件跳转,比如点击按钮

// 在User.vue下
<button @click="clikeHandle">回首页</button>

methods:{
    clikeHandle() {
      this.$router.push("/");
      // this.$router.replace("/"); 也能跳转
      // 区别:push可以叠加缓存,从a跳转到b,能返回a
      // replace不能退换原页面
    }
  }

命名路由

修改跳转方式

// 在main.js下
    { path: "/User/:useid/:name", component: User,name:"User" },

// 在APP.vue下
<router-link :to="{ name:'User', params:{useid:100001, name:'pandeng'}}">Go to User</router-link> |

对编程式导航也能实现跳转

methods:{
    clikeHandle() {
        this.$router.push({name:"Home"});
    }
  }

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default

具体业务: 想在各个页面都增加一个广告

<!-- 在pages下创建新文件AD.vue -->
<div>
    <h3>广告页面</h3>
</div>

<!-- 在index.js下导入ad -->
import Advertisement from "../pages/AD.vue"

<!-- 修改想要插入页面的component,将其改为components,如果想应用到全部页面,就把所有的components都改一遍 -->
{ 
path: "/", 
components: {
    default:Home,
    Ad: Advertisement,
},
name:"Home" 
},

<!-- 在APP.vue下新增一个出口,这里的name对应回刚才修改components中Advertisement的key--Ad -->
<router-view name="Ad"></router-view>

重定向与别名

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

具体业务:现在当我们打开News页面的时候,既不显示体育新闻也不显示娱乐新闻,我们想让他默认显示一个东西

// 在index.js文件中 与path: "/News", 同级对象下
redirect:"/News/Sports_new",

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

业务逻辑:用户不小心输出页面,将Home输为home,但是我们仍能让其访问

// 在index.js 与path: "/", 同级下
alias:"/home",

HTML5的History模式

现在我们的页面默认是带有#的,我们想去掉这个可以在路由中设置mode

// 创建路由对象
const router = new VueRouter({
    mode:"history",
    // mode:"hash", 默认hash模式
    routes,
})

当你使用 history 模式时,URL 就像正常的 url,例如 http://localhost:8080/News/Sports_new,也好看!

不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://localhost:8080/News/Sports_new 就会返回 404,这就不好看了。

所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

报错解决

如果报错 Error:Can‘t resolve ‘vue/types/umd‘ in ......

可能是main.js中出现这一行,删掉即可

出错代码

Router进阶

路由导航

“导航”表示路由正在发生改变。vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

全局前置守卫

// 在index.js创建路由对象下
router.beforeEach((to,from,next) =>{
    console.log(from);  // 当前导航正要离开的路由
    console.log(to); //  即将要进入的目标 路由对象

    next(); // 允许跳转
})

next函数,是一个钩子函数,执行效果依赖 next 方法的调用参数。

next钩子函数

  • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
  • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto prop 或 router.push 中的选项。
  • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

全局解析守卫

可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

全局后置钩子

前置是跳转之前发生,后置是跳转之后发生

// 在index.js创建路由对象下
router.afterEach((to,from) =>{
    console.log(to,from);
})

路由独享的守卫

可以在路由配置上直接定义 beforeEnter 守卫

// 在index.js的想要设置路由的配置上(与path: "/", 同级)
beforeEnter:(to,from,next)=>{
        console.log(to,from);
        next();
    },

组件内的守卫

可以在路由组件内直接定义以下路由导航守卫

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
// 在Home.vue中与data()同级下
beforeRouteEnter(to, from,next){
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    console.log(to,from);
    next();
  },
  beforeRouteUpdate(to, from,next){
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
    console.log(to,from);
    next();
  },
  beforeRouteLeave(to, from,next){
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
    console.log(to,from);
    next();
  },

完整的导航解析流程

  • 1.导航被触发。
  • 2.在失活的组件里调用 beforeRouteLeave 守卫。
  • 3.调用全局的 beforeEach 守卫。
  • 4.在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  • 5.在路由配置里调用 beforeEnter。
  • 6.解析异步路由组件。
  • 7.在被激活的组件里调用 beforeRouteEnter。
  • 8.调用全局的 beforeResolve 守卫 (2.5+)。
  • 9.导航被确认。
  • 10.调用全局的 afterEach 钩子。
  • 11.触发 DOM 更新。
  • 12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

路由原信息

定义路由的时候可以配置 meta 字段

具体业务:用户登录了才能进入用户首页,不登录进不去

// 在index.js中,User路由下,与path: "/User/:useid/:name", 同级下
meta:{
    isLogin:true,
}

// 然后在下方全局前置守卫处
router.beforeEach((to,from,next) =>{
    // console.log(from);  // 当前导航正要离开的路由
    // console.log(to); //  即将要进入的目标 路由对象
    if(to.meta.isLogin){
        // 判断用户是否已经登录
        const token = true;
        if(token){
            next(); // 允许跳转
        }else{
            next("/Login");
        }
    }else {
        next();
    }
})

路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

具体业务: 我们加载首页的时候其实不需要加载新闻下的路由,可以等到点进新闻界面再加载

// 在index.js下,去掉原本的import

// import Sports_new from "../pages/newsub/sports_new.vue"
// import Entertainment_new from "../pages/newsub/entertainment_new.vue"

// 在News路由下
children:[
        {path: "Sports_new", 
        component:() => import("../pages/newsub/sports_new.vue"),},
        {path: "Entertainment_new", 
        component:() => import("../pages/newsub/entertainment_new.vue"),},
    ]