vue-router 运行机制 及 底层原理

1.测试页面

index.html

<!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

<!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

<!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

SPA_RESOLVE_INIT = function (transition) {
	document.getElementById("content").innerHTML = "当前是渲染的页面";
}

list.js

SPA_RESOLVE_INIT = function (transition) {
	document.getElementById("content").innerHTML = "当前是渲染的页面";
}

myroute.js

(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(); // 注册到全局
})();

.

posted @ 2017-07-19 22:15  每天都要进步一点点  阅读(1198)  评论(0编辑  收藏  举报