vue-router 运行机制 及 底层原理
1.测试页面
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Document</ title > < style > .router-link-active{color: red;} </ style > </ head > < body > <!-- 路由:异步加载 --> <!--VueJs核心库--> < script src="vue.js"></ script > <!--Router--> < script src="vue-router.js"></ script > < div id="app"> < h1 >Hello App</ h1 > <!--router-link被渲染成a标签,为什么直接用a标签而用router-link?--> < router-link to="/index">Go to Index</ router-link > < router-link to="/subpage">Go to SubPage</ router-link > <!--渲染位置--> < router-view ></ router-view > </ div > < script > //VueJS的router-link,在没有使用之前,不会对任何Tag(标签)起到任何作用 //const和var一样都是声明变量的,ES6语法,const(声明常量) //两套模板 const Foo = {template:'< div >Index</ div >'} const Bar = {template:'< div >SubPage</ div >'} const routes = [ // 配置 //{路由名称:名字和路径,模板:模板的变量} {path:'/index',component:Foo}, {path:'/subpage',component:Bar} ] const router = new VueRouter({ // 得到VueRouter的实例 routes }); // new Vue({ // el:"#app", // 指定渲染位置 // data:{ // 数据 // message:'Hello App' // } // }); const app = new Vue({ //在一个地方传入的是一个对象,需要一对大括号 router }).$mount('#app'); //指定位置 </ script > </ body > </ html > |
index2.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Document</ title > < style > .router-link-active{color: red;} </ style > </ head > < body > < div id="app"> < div > < router-link to="/user/foo">/user/foo</ router-link > </ div > < div > < router-link to="/user/bar">/user/bar</ router-link > </ div > < div > < router-view ></ router-view > </ div > </ div > <!--VueJs核心库--> < script src="vue.js"></ script > <!--Router--> < script src="vue-router.js"></ script > <!--配置动态路由--> < script > const User = { template:`< div >User:{{$route.params.id}}</ div >` } const router = new VueRouter({ routes:[ {path:'/user/:id',component:User} ] }); const app = new Vue({router}).$mount('#app'); </ script > </ body > </ html > |
2.函数封装
index3.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Document</ title > < style > .router-link-active{color: red;} </ style > </ head > < body > < a href="#/index?index=1">异步加载首页</ a > < a href="#/list?list=1">异步加载列表</ a > < a href="#/detail?detail=1">异步加载详情</ a > < a href="#/detail2?detail2=1">异步加载详情2</ a > < div id="content"> 默认 </ div > < script src="myroute.js"></ script > < script > // window.addEventListener('hashchange',function() { // 监听URL的改变 // console.log("Hello"); // }); spaRouters.init(); /* 1.开发都是异步的 */ spaRouters.map("/index",function(transition){ spaRouters.asyncFun("index.js",transition) }) spaRouters.map("/list",function(transition){ spaRouters.asyncFun("list.js",transition) }) </ script > </ body > </ html > |
index.js
1 2 3 | SPA_RESOLVE_INIT = function (transition) { document.getElementById( "content" ).innerHTML = "当前是渲染的页面" ; } |
list.js
1 2 3 | SPA_RESOLVE_INIT = function (transition) { document.getElementById( "content" ).innerHTML = "当前是渲染的页面" ; } |
myroute.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | ( function () { // 匿名函数,让代码处于局部 // 通过监听,改变页面的显示 function spaRouters() { this .routers = {}; // 保存注册所有路由,也可以理解为缓存 } var util = { // 声明公共类 getParamsUrl: function (){ // 获取路由的路径和参数 var hasDetail = location.hash.split( "?" ); var hasName = hasDetail[0].split( "#" )[1]; // 得到路由地址 var params = hasDetail[1]?hasDetail[1].split( "&" ):[]; // 得到参数 var query = {}; for ( var i = 0; i < params.length; i++) { var item = params[i].split( "=" ); query[item[0]] = item[1]; } return { path:hasName, query:query }; // 返回一个路由名称 } } // 一块业务 spaRouters.prototype = { init: function (){ var self = this ; window.addEventListener( 'hashchange' , function () { // 监听URL的改变 // 只是知道发生了改变,并不知道路径,需要路由处理 self.urlChange(); }); window.addEventListener( 'load' , function () { // 监听URL的改变 // 只是知道发生了改变,并不知道路径,需要路由处理 self.urlChange(); }); }, refresh: function (currentHash){ // 加载 var self = this ; if (self.beforeFun) { self.beforeFun({ to:{ path:currentHash.path, query:currentHash.query }, next: function (){ self.routers[currentHash.path].callback.call(self,currentHash); } }) } else { self.routers[currentHash.path].callback.call(self,currentHash); } }, // URL 路由处理 urlChange: function (){ var currentHash = util.getParamsUrl(); if ( this .routers[currentHash.path]){ this .refresh(currentHash); } }, // 仅仅作为注册路由 map: function (path,callback){ // 清除空格 path = path.replace(/\s*/g, "" ); // 过滤空格 if (callback && Object.prototype.toString.call(callback) === "[object Function]" ){ this .routers[path] = { callback:callback, fn: null // 缓存异步文件状态 } } else { console.trace( "注册" +path+ "需要注册回调信息" ); } }, asyncFun: function (file,transition){ var self = this ; if (self.routers[transition.path].fn){ self.afterFun && self.afterFun(transition) self.routers[transition.path].fn(transition) } else { console.log( "开始异步下载js文件" +file); var _body = document.getElementsByTagName( "body" )[0]; var scriptEle = document.createElement( "script" ); scriptEle.type = 'text/javascript' ; scriptEle.src = file; scriptEle.async = true ; SPA_RESOLVE_INIT = null ; scriptEle.onload = function (){ // 加载文件之后 console.log( "下载" +file+ "完成" ); self.afterFun && self.afterFun(transition) self.routers[transition.path].fn = SPA_RESOLVE_INIT; self.routers[transition.path].fn(transition) } _body.appendChild(scriptEle); } } } window.spaRouters = new spaRouters(); // 注册到全局 })(); |
.
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步