1.Vue Router 源码学习笔记4 - pushState和replaceState的实现
2.vue-router源码三、理解Vue-router中的Matcher
3.vueè·¯ç±ï¼äºçº§è·¯ç±å跳转
4.vue-router源码六、router.resolve源码解析
Vue Router 源码学习笔记4 - pushState和replaceState的实现
在Vue Router中,HTML5History的push和replace操作主要通过util/push-state.js中的相应函数来执行,它们依赖window.history.pushState和window.history.replaceState API。对于HTML5History,源码工具审核基准如果浏览器支持,就按照标准流程进行,即利用pushState或replaceState改变浏览器的历史记录,而不会导致页面刷新。
对于HashHistory,浏览器支持与否对操作方式有影响。opengl架构源码若支持,同样采用类似方法,通过pushState设置hash部分,replaceState则调用window.location.replace替换当前URL。然而,如果浏览器不支持pushState,会直接操作window.location更改URL,以#符号为标志。
MDN文档中提到,pushState需要三个参数:状态对象、标题(通常忽略)和可选的epr系统源码URL。而replaceState与pushState类似,只是替换当前历史项,而非新增,尽管它会在浏览器历史中生成新的记录。
当路由更改后,紧接着是视图的同步更新。详细了解这两个方法的使用,可以参考MDN文档:developer.mozilla.org/zh-CN/docs/Web/API/History/pushState。
继续深入学习,确保在实际项目中正确运用这些原理,实现无缝的更名器 源码路由切换。
vue-router源码三、理解Vue-router中的Matcher
在深入探究vue-router的内部机制时,我们关注的重点是Matcher的实现。这个系列文章基于vue-router v4.0.的源码,如果你尚未熟悉vue-router的基本用法,建议先通过官网学习。
Matcher在vue-router中的角色至关重要,它是每个定义路由的转换器,负责路由的创建、修改和删除。createRouter函数通过createRouterMatcher生成Matcher,jetty源码解读它接收路由表routes和全局选项globalOptions作为输入。
在createRouterMatcher中,首先创建matchers和matcherMap来存储处理后的RouteRecordMatcher。遍历routes,调用addRoute方法对每个路由进行处理。addRoute处理新路由时,会标准化路由信息,如果新路由是别名,则将其关联到原始记录的aliasOf属性。
addRoute还会处理路由的别名,生成新的matcher,并递归处理子路由。最后,它返回一个删除原始matcher的方法。createRouteRecordMatcher是addRoute的重要部分,它根据token数组(如/:id(\\d+)new)生成正则表达式和解析器。
token是解析路径的关键,它定义了路径的结构,包括静态部分和动态参数。tokenizePath函数通过有限状态机将路径转换成token数组。tokensToParser则根据token构建正则表达式和处理函数,用于解析和生成路径。
createRouteRecordMatcher利用上述工具,构建最终的matcher,包含了路径信息、动态参数处理、权重计算等功能。Matcher的存储机制也值得注意,matchers数组按照权重排序,而matcherMap则只保存原始路由的记录,便于按名称查询。
总的来说,Matcher是vue-router实现路由匹配和管理的核心组件,它通过token数组和相关函数,实现了路由的高效管理和解析。
vueè·¯ç±ï¼äºçº§è·¯ç±å跳转
â routeræ件ä¸çindex.jsæ件ï¼
/* å¯¼å ¥Vueæé å½æ° */
import Vue from 'vue'
/* å¯¼å ¥è·¯ç±VueRouteræé å½æ° */
import VueRouter from 'vue-router'
/* å¯¼å ¥HomeViewé¡µé¢ */
import HomeView from '../views/HomeView.vue'
//è°ç¨æé å½æ°Vueçuseæ¹æ³ ä¼ å ¥VueRouteræé å½æ°
//ä½ç¨æ¯æVueRouterä½ä¸ºä¸ä¸ªæ件 å ¨å±æå ¥å°Vueä¸
Vue.use(VueRouter)
/* å®ä¹ä¸ä¸ªè·¯ç±æ°ç»å¯¹è±¡ */
const routes = [
/* ä¸ä¸ªå¯¹è±¡å°±å¯¹åºäºä¸ä¸ªè·¯ç±
pathå°±æ¯è·¯ç±çå°å
nameç»è·¯ç±èµ·çåå
component å ·ä½è·³è½¬ç页é¢
*/
{
/* path: '/' æ ¹é¡µé¢,表示已è¿å ¥å°±æ¾ç¤ºçé¡µé¢ */
path: '/',
name: 'home',
/* è¿ç§æ¹å¼ä¸è¿å ¥é¡µé¢å°±ä¼å ¨é¨å è½½,ä¸æ¯ç¨å°çæ¶ååå è½½
æ§è½æ²¡ææå è½½çæ¹å¼å¥½ */
component: HomeView,
/* å¯ä»¥ä½¿ç¨redirect éå®å å·²è¿å ¥ä¸»é¡µå°±å±ç¤ºç¬¬ä¸ä¸ªå页é¢
redirect åé¢è·çæ¯è·¯å¾å 并ä¸æ¯name */
/* å 为/æ¯æ ¹è·¯å¾ ææå¯ä»¥ç´æ¥åone */
redirect:'one',
children:[{
path:'one',
name:'one',
component: () => import('../views/OneView.vue')
}]
},
{
/* è¿éæ¯ä¸çº§ç®å½æ以å¯ä»¥å / è¡¨ç¤ºæ ¹ç®å½ */
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
/* æå è½½åè½ : ä¸å¼å§ä¸å è½½,å½ä½ åæ¢è·¯ç±çæ¶ååå è½½ */
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue'),
/* aboutä¸æ¯æ ¹è·¯å¾ æ以redirectåé¢è¦åå ¨ '/about/aboutchild', */
redirect:'/about/aboutchild',
children:[{
path:'aboutchild',
name:'aboutchild',
component: () => import('../views/AboutChild.vue')
}]
},
{
path:'/ChildA',
name:'ChildA',
component: () => import('../components/ChildA.vue')
},
{
/* path:'*' å¿ é¡»è¦æ¾æå */
/* path:'*' 表示ä¸é¢çè·¯ç±æ²¡æå¹é å° åè¿å ¥ä¸é¢çé¡µé¢ */
path:'*',
name:'notfound',
component: () => import('../components/NotFound.vue')
}
]
/* å®ä¾åæé å½æ° VueRouter 产çä¸ä¸ªå®ä¾å对象
并æä¸é¢çè·¯ç±æ°ç»å¯¹è±¡routeså½ä½åæ° ä»¥å¯¹è±¡çæ¹å¼ä¼ ç»æé å½æ° VueRouter*/
const router = new VueRouter({
routes
})
/* æå®ä¾åè·¯ç±å¯¹è±¡ routeré»è®¤å¯¼åº */
export default router
main.jsæ件ï¼
/* å¯¼å ¥Vueæé å½æ° */
import Vue from 'vue'
/* å¯¼å ¥App.vueå ¥å£é¡µé¢ */
import App from './App.vue'
/* å¯¼å ¥routeræ件夹ä¸çindex.jsä¸çrouterå®ä¾å对象 */
/* ä¸ä¸ªæ件夹éé¢åªæä¸ä¸ªindex.jsæ件å¨èææ¶ä¸å¯ä»¥æ./router/index.jsç®å为./router */
import router from './router'
/* ç产æ示 */
/* æ¹æfalseæ¯ç¨æ¥å ³éå¼åè æ示 */
Vue.config.productionTip = false
/* å¨Vueç对象åæ°éé¢é ç½® el:"#app" çäº .$mount('#app')
é½æ¯ç¨æ¥æè½½å°id为#appçdivä¸ç*/
/* æè·¯ç±å®ä¾å对象routeré ç½®å¨Vueä¸,ä½ç¨æ¯ä¿è¯é¡¹ç®ä¸
ææçvueæ件é½å¯ä»¥ä½¿ç¨routerè·¯ç±çå±æ§åæ¹æ³ */
new Vue({
router,
/* ä¼ææævueæ件渲æå°Appç»ä»¶ä¸ */
render: h => h(App)
}).$mount('#app')/* çåäº el:"#app" */
viwesæ件ä¸ï¼
App.vueæ件ï¼
<template>
<div id="app">
<nav>
<!-- router-link ç»ä»¶æ¯è´è´£è·³è½¬ç toå±æ§æ¯ç¨æ¥å跳转路å¾ç
router-linkç»ä»¶æ¬è´¨ä¸æ¯æaæ ç¾æ¥å®ç°ç è·¯ç±è·³è½¬çåçæ¯æ ¹æ®
éç¹æ¥ç -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/ChildA">ç¹æ跳转ChildA</router-link> |
<router-link to="/ChildB">ç¹æ跳转ChildB</router-link> |
</nav>
<!-- router-view ç»ä»¶æ¯ç¨æ¥å±ç¤ºç»ä»¶çå®¹å¨ -->
<router-view/>
<!-- å建两个ç»ä»¶ChildA åChildB 并å两个 router-link å¯ä»¥å®ç°è·³è½¬
ç»ä»¶æ¾ç¤ºå¨ router-view 容å¨ä¸ -->
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e;
}
nav {
padding: px;
}
nav a {
font-weight: bold;
color: #2c3e;
}
/* .router-link-exact-active 跳转é¾æ¥è¢«æ¿æ´»çæ¶åå è½½å°router-linkèº«ä¸ */
nav a.router-link-exact-active {
color: #b;
}
</style>
AboutView.vueæ件ï¼
<template>
<div class="about">
<h1>This is an about page</h1>
<!-- toåé¢åçæ¯è·¯å¾ -->
<!-- <router-link to="/about/aboutchild">ææ¯aboutchild</router-link> -->
<!-- to åé¢è¦å : ä½ç¨æ¯æåé¢è§£ææä¸ä¸ªå¯¹è±¡èä¸æ¯å符串 -->
<router-link :to="{ name:'aboutchild'}">ææ¯aboutchild</router-link>
<!-- äºçº§è·¯ç±æ¾ç¤ºçå®¹å¨ -->
<router-view></router-view>
</div>
</template>
AboutChild.vueæ件ï¼
<template>
<div>
<h1>AboutChild</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
HomeView.vueæ件ï¼
<template>
<div class="home">
<h1>KWå²å²å²</h1>
<router-link to="/one">ONEview</router-link>
<!-- äºçº§è·¯ç±å¯¹åºçç»ä»¶å®¹å¨ -->
<router-view></router-view>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'HomeView',
components: {
}
}
</script>
OneView.vueæ件ï¼
<template>
<div>
<h1>ææ¯ONEVIwe</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
componentsæ件ä¸ï¼
ChildA.vueæ件ï¼
<template>
<div>
<h1>ææ¯CHildA</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
ChildB.vueæ件ï¼
<template>
<div>
<h1>ææ¯ChildB</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
NotFound.vueæ件:
<template>
<div>
<h1>ææ¯notfound</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
左边æ件ç®å½ï¼
vue-router源码六、router.resolve源码解析
vue-router源码系列带你深入了解v4.0.版本的实现,前提是对基本用法有一定了解,可通过官网学习。本文焦点是router.resolve的解析过程。
router.resolve的核心任务是将给定的路由地址标准化。它接受两个参数:rawLocation(可能为对象或字符串)和currentLocation(可选,默认为currentRoute)。解析过程分为两个分支:
parseURL函数接收query解析函数、location和currentLocation,负责处理相对路径。例如,当to='cc',from='/aa/bb'时,经过一系列resolveRelativePath操作,最终可能转换为'/aa/cc','/aa/bb/cc'等。特别地,如果from路径以'/ '开始,无论to如何,resolveRelativePath始终返回'/cc'。
解析完rawLocation后,调用matcher.resolve进一步处理,这个阶段会根据匹配规则进行更复杂的路径处理。
最终,router.resolve返回一个标准化后的路由对象,包含了处理后的路径信息和其他相关数据,为后续的导航操作提供依据。