文章目录
一、hash模式与history模式的实现原理
1. hash模式
原理:通过window.location.hash获取到当前url的hash;hash模式下通过hashchange方法可以监听url中hash的变化
hash模式是vue-router的默认路由模式,它的标志是在域名之后带有一个#
http://localhost:8888/#/home
* 通过window.location.hash获取到当前url的hash;
eg:let path = window.location.hash || "#1"
* 通过a标签或者location.assign(url)进行页面切换例如:
<a href="#1" @click="change">去1号组件</a>
document.location.assign('https://developer.mozilla.org/zh-CN/docs/Web/API/Location/reload');
* hash模式下通过hashchange方法可以监听url中hash的变化
window.removeEventListener("hashchange", this.route,false)
window.addEventListener("hashchange", this.route,false)
2.history模式
原理:通过location.pathname获取到当前url的路由地址;history模式下,通过pushState和replaceState方法可以修改url地址,结合popstate方法监听url中路由的变化
history模式下的路由更加美观
http://localhost:8888/home
*通过location.pathname获取到当前url的路由地址;
let path = window.location.pathname || "/1"
*history模式下,通过pushState和replaceState方法可以修改url地址,
<a href="/1" @click.prevent="change">去1号组件</a>
const change=(e)=> {
// path=e.target.getAttribute("href") 这种方法也可以用但是刷新页面后会跳到首页
window.history.pushState(null,"page1",e.target.getAttribute("href"))
path = window.location.pathname
console.log(path)
Component = RouteTable[path.toString()]
if (!Component) {
component.value = 'Component404'
} else {
component.value = RouteTable[path.toString()]
}
},
二、vue-router
1.创建路由并挂载
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)
app.mount('#app')
2.组件内使用路由
<div id="app">
<h1>Hello App!</h1>
<p>
<!--使用 router-link 组件进行导航 -->
<!--通过传递 `to` 来指定链接 -->
<!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
3.动态路由
{ path: '/users/:id', component: User }, //现在像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。
组件内通过route.params.id 获取路由id的参数
4. 404路由
const routes = [
// 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
// 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
{ path: '/user-:afterUser(.*)', component: UserGeneric },
]
5. 路由匹配
const routes = [
在参数中自定义正则
// /:orderId -> 仅匹配数字
{ path: '/:orderId(\\d+)' },
// /:productName -> 匹配其他任何内容
{ path: '/:productName' },
可重复的参数
// /:chapters -> 匹配 /one, /one/two, /one/two/three, 等
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
{ path: '/:chapters*' },
可重复的参数
// 仅匹配数字
// 匹配 /1, /1/2, 等
{ path: '/:chapters(\\d+)+' },
// 匹配 /, /1, /1/2, 等
{ path: '/:chapters(\\d+)*' },
可选参数
// 匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
// 匹配 /users 和 /users/42
{ path: '/users/:userId(\\d+)?' },
]
6.导航到不同的位置
api
router.push(...)
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。你需要提供路由的 name 或手写完整的带有参数的 path :
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
router.replace(...)
它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
router.go(...)
// 向前移动一条记录,与 router.forward() 相同
router.go(1)
// 返回一条记录,与router.back() 相同
router.go(-1)
// 前进 3 条记录
router.go(3)
7.命名路由
const routes = [
{
path: '/user/:username',
name: 'user',
component: User
}
]
<router-link :to="{ name: 'user', params: { username: 'erina' }}">
User
</router-link>
router.push({ name: 'user', params: { username: 'erina' } })
8.命名视图
如果 router-view 没有设置名字,那么默认为 default
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar:LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar:LeftSidebar,
},
},
],
})
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
9.重定向和别名
redirect
重定向是指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /
const routes = [
{ path: '/home', redirect: '/' },
{
// /search/screens -> /search?q=screens
path: '/search/:searchText',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return { path: '/search', query: { q: to.params.searchText } }
},
},
]
alias
将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。
const routes = [
{ path: '/', component: Homepage, alias: '/home' },
{
path: '/users',
component: UsersLayout,
children: [
// 为这 3 个 URL 呈现 UserList
// - /users
// - /users/list
// - /people
{ path: '', component: UserList, alias: ['/people', 'list'] },
],
},
]
10.导航守卫
to: 即将要进入的目标 用一种标准化的方式
from: 当前导航正要离开的路由 用一种标准化的方式
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
完整的导航解析流程
导航被触发。
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫(2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
10.路由元信息
有时,你可能希望将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的meta属性来实现,并且它可以在路由地址和导航守卫上都被访问到。定义路由的时候你可以这样配置 meta 字段:
const routes = [
{
path: '/posts',
component: PostsLayout,
children: [
{
path: 'new',
component: PostsNew,
// 只有经过身份验证的用户才能创建帖子
meta: { requiresAuth: true }
},
{
path: ':id',
component: PostsDetail
// 任何人都可以阅读文章
meta: { requiresAuth: false }
}
]
}
]
router.beforeEach((to, from) => {
// 而不是去检查每条路由记录
// to.matched.some(record => record.meta.requiresAuth)
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
// 此路由需要授权,请检查是否已登录
// 如果没有,则重定向到登录页面
return {
path: '/login',
// 保存我们所在的位置,以便以后再来
query: { redirect: to.fullPath },
}
}
})
11.过渡动效
<router-view v-slot="{ Component }">
<transition name="fade">
<component :is="Component" />
</transition>
</router-view>
上面的用法会对所有的路由使用相同的过渡。如果你想让每个路由的组件有不同的过渡,你可以将元信息和动态的 name 结合在一起,放在 上
const routes = [
{
path: '/custom-transition',
component: PanelLeft,
meta: { transition: 'slide-left' },
},
{
path: '/other-transition',
component: PanelRight,
meta: { transition: 'slide-right' },
},
]
<router-view v-slot="{ Component, route }">
<!-- 使用任何自定义过渡和回退到 `fade` -->
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
滚动
注意: 这个功能只在支持 history.pushState 的浏览器中可用。
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
如果返回一个 falsy 的值,或者是一个空对象,那么不会发生滚动。
const router = createRouter({
history: createWebHashHistory(),
routes: [...],
scrollBehavior (to, from, savedPosition) {
// 始终滚动到顶部
return { top: 0 }
}
})
路由懒加载
// 将
// import UserDetails from './views/UserDetails'
// 替换成
const UserDetails = () => import('./views/UserDetails')
const router = createRouter({
// ...
routes: [{ path: '/users/:id', component: UserDetails }],
})
三、
github链接
router