一、创建 Vue2 项目, 下载 vue-router
npm i -g @vue/cli-init
vue init webpack project_name
二、SPA(单页面富应用)
🍀 Single Page web Application
🍀 整个网站只有一个 html 页面
🍀 网站内容依然很丰富(在使用者看来依然是很多个页面)
🍀 前端的
vue router
控制前端页面的映射关系(映射关系告诉我们哪个 url 路径对应哪个组件的内容)
- SPA 前端维护一套路由规则
- 网页 URL 改变的时候,页面不会进行整体的刷新
- 如何实现(看下面)
三、hash 和 history(网页 URL 改变的时候页面不进行整体的刷新)
如何实现地址栏 URL 改变的时候页面不进行整体的刷新 ?
(1) URL 的 hash
- URL 的 hash:也叫做锚点(#),本质上是改变
window.location 的 href 属性
- 可通过直接赋值
location.hash
来改变 href,且页面不会刷新
(2) HTML5 的 history 模式:pushState
🍀 类似栈数据结构
🍀
history.back()
出栈🍀
history.pushState()
入栈🍀
history.replaceState()
把当前页面覆盖掉(无法看到之前的页面)🍀
history.go()
浏览器地址修改【-1: 上个页面、-2: 倒数第二个页面】🍀
history.forward()
前进页面
四、vue-router 介绍
- vue-router 是 Vue.js 官方的路由插件,它和 Vue.js 深度集成,适合用于构建单页面应用
- 学习网站:https://router.vuejs.org/zh/
- vue-router 是基于路由和组件的
✏️ 路由用于设定访问路径,把路径和组件映射起来
✏️ 在 vue-router 的单页面应用中,页面路径的改变就是组件之间的切换
五、安装和使用 vue-router
npm install vue-router --save
- 导入路由对象,并调用
Vue.use(VueRouter)
- 创建路由实例,传入路由映射配置
- 在 Vue 实例中挂载创建的路由实例
/router/index.js
import Vue from 'vue' // 用于安装【路由】插件 import Router from 'vue-router' // 导入路由对象 // 安装【路由】插件 Vue.use(Router) const routes = [ // routes 用于配置路由和组件之间的映射关系 ] export default new Router({ // 创建并导出路由对象(在 main.js 中导入该路由对象) routes })
main.js
import Vue from 'vue' import App from './App' import router from './router' // 导入路由对象 Vue.config.productionTip = false new Vue({ el: '#app', router, // 将路由对象挂载到 Vue 实例中 render: h => h(App) })
六、路由和组件的映射
- ① 创建路由组件(项目所需组件)
- ② 配置路由映射:组件和路径的映射关系
- ③ 使用路由:通过
<router-link>
和<router-view>
Home.vue
<template> <div id="container"> Home.vue </div> </template> <script> export default { name: "Home", }; </script> <style scoped> #container { background: green; } </style>
<template> <div id="container"> About.vue </div> </template> <script> export default { name: "About", }; </script> <style scoped> #container { background: purple; } </style>
/router/index.js
import Vue from 'vue' // 用于安装【路由】插件 import Router from 'vue-router' // 导入路由对象 import Home from '../components/Home'; import About from '../components/About'; // 安装【路由】插件 Vue.use(Router) const routes = [ // routes 用于配置路由和组件之间的映射关系 { path: '/home', component: Home }, { path: '/about', component: About } ] export default new Router({ // 创建并导出路由对象(在 main.js 中导入该路由对象) routes })
main.js
import Vue from 'vue' import App from './App' // App 组件会被 Vue 实例加载, App 组件中的代码会被解析 import router from './router' // 导入路由对象 Vue.config.productionTip = false new Vue({ el: '#app', router, // 将路由对象挂载到 Vue 实例中 render: h => h(App) })
App.vue
<template> <div id="app"> <!-- 【route-link】是 vue-router 插件中的组件 --> <router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link> <!-- 渲染处理的组件内容所在位置 --> <router-view></router-view> </div> </template> <script> export default { name: "App", }; </script> <style> </style>
✏️
<router-link>
是 vue-router 中的一个组件,最终会被解析为<a>
标签✏️
<router-view>
会根据当前的路径动态渲染出不同的组件✏️ 网页的其他内容(如 顶部的标题,或底部的版权信息)会和
<router-view>
处于同一级
✏️ 路由切换的时候,切换的是
<router-view>
挂载的组件,其他内容不会发生改变
const routes = [ // routes 用于配置路由和组件之间的映射关系 { // 默认访问的是【Home】组件的内容(路由的默认值) path: '', redirect: '/home' // 重定向到首页 }, { path: '/home', component: Home }, { path: '/about', component: About } ]
export default new Router({ // 创建并导出路由对象(在 main.js 中导入该路由对象) routes, mode: 'history' // history 的形式修改浏览器路径 })
七、router-link 的其他属性
tag
: 默认 router-link
会被渲染为 <a></a>
, 该属性可设定 router-link
被渲染为其他的标签
<template> <div id="app"> <!-- 【route-link】是 vue-router 插件中的组件 --> <router-link to="/home" tag="button">首页</router-link> <router-link to="/about" tag="button">关于</router-link> <!-- 渲染处理的组件内容所在位置 --> <router-view style="margin: 9px"></router-view> </div> </template>
replace 属性
: 不会留下 history 记录,后退键不会返回上一页面
active-class 属性
:当<router-link>
对应的路由匹配成功时,会自动给当前元素设置一个名为【router-link-active】的 class(样式) ;该属性可以修改它的默认名称;在进行高亮显示导航菜单或底部 tabbar 的时候,会使用到该属性;一般都是直接使用该类名
<template> <div id="app"> <!-- 【route-link】是 vue-router 插件中的组件 --> <router-link to="/home" tag="button" active-class="active-class" >首页</router-link> <router-link to="/about" tag="button">关于</router-link> <!-- 渲染处理的组件内容所在位置 --> <router-view style="margin: 9px"></router-view> </div> </template>
八、this.$router.push() 路由跳转
<template> <div id="app"> <button @click="clickHome" >首页跳转</button> <button @click="clickAbout" >关于跳转</button> <router-view style="margin: 9px"></router-view> </div> </template> <script> export default { name: "App", methods: { clickHome() { this.$router.push('home') }, clickAbout() { // this.$router.replace('home') this.$router.push('about') } }, }; </script>
九、动态路由
const routes = [ // routes 用于配置路由和组件之间的映射关系 { // 默认访问的是【Home】组件的内容(路由的默认值) path: '', redirect: '/home' // 重定向到首页 }, { path: '/home', component: Home }, { path: '/user/:userId', // 动态路由 component: User } ]
<template> <div id="container"> User.vue <div>用户id: {{ $route.params.userId }}</div> <div style="margin: 19px; color: orange">用户id: {{ userId }}</div> </div> </template> <script> export default { name: "User", computed: { userId() { return this.$route.params.userId; }, }, }; </script> <style scoped> #container { background: yellow; } </style>
$route
处于活跃状态的哪个组件
十、路由懒加载
懒加载:用到的时候再加载
打包应用的时候,Javascript 包会变得非常大,进而影响页面加载。如果能够把不同路由对应的组件分割为不同的代码块,当路由被访问的时候才加载对应组件,这样就更加高效了。
import Vue from 'vue' import Router from 'vue-router' // 路由懒加载 const User = ()=> import('../components/User') Vue.use(Router) const routes = [ { path: '', redirect: '/home' }, { path: '/home', component: ()=> import('../components/Home') // 路由懒加载 }, { path: '/about', component: ()=> import('../components/About') // 路由懒加载 }, { path: '/user/:userId', // 动态路由 component: User } ]
十一、嵌套路由
嵌套路由是个很常见的功能:
① 在 home 页面中,希望通过
/home/news
和/home/message
访问不同的内容② 一个路径映射一个组件,访问两个不同的路径会分别渲染不同的两个组件
实现嵌套路由的两个步骤:
- 创建对应的子组件,并在路由映射中配置对应的子路由
- 在组件内部使用
<router-view>
标签
const routes = [ // routes 用于配置路由和组件之间的映射关系 { // 默认访问的是【Home】组件的内容(路由的默认值) path: '', redirect: '/home' // 重定向到首页 }, { path: '/home', component: ()=> import('../components/Home'), // 路由懒加载 children: [ // 子路由/嵌套路由 { path: '/', redirect: 'news' }, { path: 'news', component: ()=> import('../components/HomeNews') }, { path: 'message', component: ()=> import('../components/HomeMessage') } ] }, { path: '/about', component: ()=> import('../components/About') // 路由懒加载 }, { path: '/user/:userId', // 动态路由 component: User } ]
<template> <div id="container"> Home.vue <router-link to="/home/news">新闻</router-link> <button @click="clickMessage">消息</button> <router-view></router-view> </div> </template> <script> export default { name: "Home", methods: { clickMessage() { this.$router.push("/home/message") } }, } </script>
十二、路由传参
- 配置路由格式:【/router/:id】
- 传递方式:【在 path 后面跟上对应的值】
- 创建后形成的路径格式:【/router/11、/router/256】
- 配置路由格式:/router(普通配置)
- 传递方式:对象中使用 query 的 key 传递参数
- 传递后形成的路径:/router?id=11、/router?id=256
<template> <div id="app"> <button @click="clickProfile" >我的1</button> <router-link :to="{path: '/profile', query: { name: '杨天荣', gender: '男' }}" >我的2</router-link> <router-view style="margin: 9px"></router-view> </div> </template> <script> export default { name: "App", methods: { clickProfile() { this.$router.push({path: '/profile/', query: { name: 'ytr', sex: 'boy', age: 6 }}) } }, }; </script>
<template> <div id="container"> Profile.vue <div> {{ $route.query }} </div> <ul> <li>{{ userInfo }}</li> </ul> </div> </template> <script> export default { name: "Profile", data() { return { userInfo: {}, }; }, created() { this.userInfo = this.$route.query; }, }; </script>
十三、vue-router 导航守卫
导航守卫:监听路由之间的跳转
import Vue from 'vue' // 用于安装【路由】插件 import Router from 'vue-router' // 导入路由对象 // 路由懒加载 const User = () => import('../components/User') // 安装【路由】插件 Vue.use(Router) const routes = [ // routes 用于配置路由和组件之间的映射关系 { // 默认访问的是【Home】组件的内容(路由的默认值) path: '', redirect: '/home' // 重定向到首页 }, { path: '/home', component: () => import('../components/Home'), // 路由懒加载 meta: { title: '首页' }, children: [ // 子路由/嵌套路由 { path: '/', redirect: 'news' }, { path: 'news', component: () => import('../components/HomeNews') }, { path: 'message', component: () => import('../components/HomeMessage') } ] }, { path: '/about', meta: { title: '关于' }, component: () => import('../components/About') // 路由懒加载 }, { path: '/user/:userId', // 动态路由 meta: { title: '用户' }, component: User }, { path: '/profile', meta: { title: '我的' }, component: () => import('../components/Profile') } ] const router = new Router({ // 创建并导出路由对象(在 main.js 中导入该路由对象) routes, mode: 'history' // history 的形式修改浏览器路径 }) /** * from: 从哪个组件(路由)来 * to: 到哪个组件(路由)去 * next: 执行下一步(必须调用一次, 否则路由不会往下执行) */ router.beforeEach((to, from, next) => { // 当切换组件的时候, 修改页面标题 window.document.title = to.matched[0].meta.title next() }) export default router
- 后置钩子(afterEach)不需要调用 next()
- 上面使用的导航守卫是全局守卫
路由独享的守卫
组件内的守卫
十四、keep-alive
router-view
是 vue-router 的组件,若被直接包含在<keep-alive>
中,则路径匹配到的试图组件会被缓存keep-alive
是 Vue 内置的组件,可以使被包含的组件保留状态,避免重复渲染
keep-alive
的两个属性:
- include: 字符串或正则,只有匹配的组件会被缓存
- exclude:字符串或正则,任何匹配的组件都不会被缓存