实现一个原生的路由系统
- 先看核心代码
function Router(){
this.routes={};
this.currentUrl='';
}
Router.prototype.route=function(path,callback){
this.routes[path]=callback||function(){}; //保证回调的时候不报错
}
Router.prototype.refresh=function(){
this.currentUrl=location.hash.slice(1)||'/'; //location.hash 指的是url 最后#后面的数据
this.routes[this.currentUrl]();//调用 callback函数
}
Router.prototype.init=function(){
window.addEventListener('load',this.refresh.bind(this),false);
window.addEventListener('hashchange',this.refresh.bind(this),false);
}
window.Router=new Router();
window.Router.init();
- 具体的效果html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试javascript路由</title>
<script type="text/javascript">
function Router(){
this.routes={};
this.currentUrl='';
}
Router.prototype.route=function(path,callback){
this.routes[path]=callback||function(){}; //保证回调的时候不报错
}
Router.prototype.refresh=function(){
this.currentUrl=location.hash.slice(1)||'/'; //location.hash 指的是url 最后#后面的数据
this.routes[this.currentUrl]();//调用 callback函数
}
Router.prototype.init=function(){
window.addEventListener('load',this.refresh.bind(this),false);
window.addEventListener('hashchange',this.refresh.bind(this),false);
}
window.Router=new Router();
window.Router.init();
</script>
</head>
<body>
<div>路由系统Router对象实现,主要提供三个方法</div>
<ul>
<li>init 监听浏览器url hash更新事件</li>
<li>route 存储路由更新时的回调到回调数组routes中,回调函数将负责对页面的更新</li>
<li>refrsh 执行当前url对应的回调函数,更新页面</li>
</ul>
<div>Demo实例,Router调用方式以及呈现效果如下:点击触发url的hash改变,并对应地更新内容,这里为更新body背景颜色</div>
<ul>
<li>
<a href="#/">变为白色</a>
</li>
<li>
<a href="#/blue">变为蓝色</a>
</li>
<li>
<a href="#/green">变为绿色</a>
</li>
</ul>
<script type="text/javascript">
var content = document.querySelector('body');
function changeBgColor(color){
content.style.backgroundColor=color;
}
Router.route('/',function(){
changeBgColor('white');
});
Router.route('/blue',function(){
changeBgColor('blue');
});
Router.route('/green',function(){
changeBgColor('green');
});
</script>
</body>
</html>
核心函数的设计的知识点
- this的奥秘
官方的解释:this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是哪个调用它的对象。
例子1
function printProduct(){
var product="橘子";
console.log(this.product);//undefined
console.log(this);//window
}
printProduct();
window.printProduct();
例子2
//这里的this指向的是对象funProduct,因为getProduct函数是通过调用funProduct.getProduct()执行的
var funProduct={
product:"橘子",
getProduct:function(){
console.log(this.product);//橘子
}
}
funProduct.getProduct();
例子3
//这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var wrapper={
product:"苹果",,
funProduct:{
product:"橘子",
getProduct:function(){
console.log(this.product);//橘子
}
}
}
wrapper.funProduct.getProduct();
例子4
//this永远指向的是最后调用它的对象,也就是看它执行的时候是谁在调用
var wrapper={
product:"苹果",,
funProduct:{
product:"橘子",
getProduct:function(){
console.log(this.product);//undefined
console.log(this);//window
}
}
}
var triggerFun = wrapper.funProduct.getProduct;
triggerFun();
- bind的奥秘
首先call
apply
bind
都能够改变函数执行的上下文对象,也就是调整改变了this的指向。
bind
方法,顾名思义,就是绑定的意思,到底是怎么绑定然后怎么用,看下面的例子。
//语法
fun.bind(this,arg1,arg2,......)
bind()方法会创建一个新的函数,称为绑定函数,fun方法在this环境下调用
该方法可传入两个参数,第一个参数作为this,第二个及以后的参数则作为函数的参数调用
创建绑定函数
this.total=1;
var mathModule={
total:2,
getTotal:function(){
return this.total;
}
};
mathModule.getTotal();//2
var getTotal_temp = mathModule.getTotal;
// getTotal在外部调用,此时的this指向了全局对象
getTotal_temp();//1
//再把getTotal_temp方法绑定到mathModule环境上
var getTotal_temp2=getTotal.bind(mathModule);
getTotal_temp2();
从上面的例子可以看出,为什么要创建绑定函数,就是当我们调用某些函数的时候是要在特定环境下才能调用到,所以我们就要把函数放在特定环境下,就是使用bind把函数绑定到特定的所需的环境下。
让函数拥有预设的参数
使用bind()方法使函数拥有预设的初始参数,这些参数会排在最前面,传给绑定函数的参数会跟在它们后面。
function list(){
//让类数组arguments拥有数组的方法slice,这个函数实现了简单把类数组转换成数组
return Array.prototype.slice.call(arguments);
}
list(1,2,3);//[1,2,3]
//给list绑定一个预设参数4
var listDefault=list.bind(undefined,4);
listDefault(); //[4]
listDefault(1,2,3);//[4,1,2,3]
setTimeout的使用
正常情况下,调用setTimeout的时候this 会指向全局对象,但是使用类的方法时我们需要指向类的实例,所以要把this,绑定要回调函数方便继续使用实例
function fun_temp1(){
this.name=1;
}
fun_temp1.prototype.fun2=function(){
window.setTimeout(this.fun3.bind(this),1000);
}
fun_temp1.prototype.fun3=function(){
console.log('name:'=this.name);//name:1
}
var fun=new fun_temp1();
fun.fun2();
快捷方法-把类数组转换成数组
第一种方法是使用apply方法
function fun(){
var slice = Array.prototype.slice;
return slice.apply(arguments);
}
fun(1,2,3);// [1,2,3]
第二种方法是使用call方法和bind方法一起使用
function fun(){
var unboundSlice = Array.prototype.slice;
// 把函数的call方法绑定在数组slice方法上,之后再给call方法传递参数
var slice = Function.prototype.call.bind(unboundSlice);
return slice(arguments);
}
fun(1,2,3);// [1,2,3]