@fantaghiro
2014-11-17T06:15:16.000000Z
字数 42225
阅读 1930
学习笔记 妙味课堂 js
//var obj = {};var obj = new Object(); //创建了一个空的对象obj.name = '小明'; //属性obj.showName = function(){ //方法alert(this.name);}obj.showName();
//var obj = {};var obj = new Object(); //创建了一个空的对象obj.name = '小明'; //属性obj.showName = function(){ //方法alert(this.name);}obj.showName();var obj2 = new Object();obj2.name = '小强';obj.showName = function(){alert(this.name);}obj2.showName();
//工厂方式:封装函数function createPerson(name){//1. 原料var obj = new Object();//2. 加工obj.name = name;obj.showName = function(){alert(this.name);};//3. 出厂return obj;}var p1 = createPerson('小明');p1.showName();var p2 = createPerson('小强');p2.showName();
/* 当new去调用一个函数:这个时候函数中的this就是创建出来的对象,而且函数的返回值直接就是this啦。(这叫做隐式返回) */// new后面调用的函数:构造函数function CreatePerson(name){this.name = name;this.showName = function(){alert(this.name);};// return obj; 隐式返回,所以这一行不用写了}var p1 = new CreatePerson('小明');p1.showName();var p2 = new CreatePerson('小强');p2.showName();
/* 当new去调用一个函数:这个时候函数中的this就是创建出来的对象,而且函数的返回值直接就是this啦。(这叫做隐式返回) */// new后面调用的函数:构造函数function CreatePerson(name){this.name = name;this.showName = function(){alert(this.name);};// return obj; 隐式返回,所以这一行不用写了}var p1 = new CreatePerson('小明');p1.showName();var p2 = new CreatePerson('小强');p2.showName();//alert(p1.showName == p2.showName); //false
/*var a = [1, 2, 3];var b = [1, 2, 3];alert(a == b); //false;*//*var a = 5;var b = a;b += a;alert(b); //8alert(a); //5 基本类型:赋值的时候只是值的复制*//*var a = [1, 2, 3];var b = a;b.push(4);alert(b); //[1, 2, 3, 4]alert(a); //[1, 2, 3, 4] 对象类型:赋值不仅是值的复制,而且也是引用的传递*//*var a = [1, 2, 3];var b = a;b = [1, 2, 3, 4];alert(b); //[1, 2, 3, 4]alert(a); //[1, 2, 3] 只要赋值就会在内存中重新生成,所以a,b互补影响*//*var a = 5;var b = 5;alert(a == b); //true 基本类型的比较:只要值相同就可以*//*var a = [1, 2, 3];var b = [1, 2, 3];alert(a == b); //false 对象类型:值和引用都相同才行*//*var a = [1, 2, 3];var b = a;alert(a == b); //true*/
var arr = [];arr.number = 10;Array.prototype.number = 20;alert(arr.number); //10 普通方法的优先级高于原型
//原型:prototype:要写在构造函数下面var arr = [1, 2, 3, 4, 5];var arr2 = [2, 2, 2, 2, 2];Array.prototype.sum = function(){var result = 0;for(var i=0; i<this.length; i++){result += this[i];}return result;}/*arr.sum = function(){var result = 0;for(var i=0; i<this.length; i++){result += this[i];}return result;}alert(arr.sum()); //15*/alert(arr.sum());alert(arr2.sum());
function CreatePerson(name){this.name = name; //变化的,不能公用的属性不能写在原型上}CreatePerson.prototype.showName = function(){alert(this.name);}var p1 = new CreatePerson('小明');var p2 = new CreatePerson('小强');alert(p1.showName == p2.showName); //true
混合的编程模式
//面向对象的写法function 构造函数(){this.属性}构造函数.原型.方法 = function(){};//面向对象的使用var 对象1 = new 构造函数();对象1.方法();
先写出普通方法
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象的选项卡</title><style>#div1 div { width: 200px; height: 200px; border: 1px solid #000; display: none; }.active { background: red; }</style><script>window.onload = function(){var oParent = document.getElementById('div1');var aInput = oParent.getElementsByTagName('input');var aDiv = oParent.getElementsByTagName('div');for(var i=0; i<aInput.length; i++){aInput[i].index = i;aInput[i].onclick = function(){for(var i=0; i<aInput.length; i++){aInput[i].className = '';aDiv[i].style.display = 'none';}this.className = 'active';aDiv[this.index].style.display = 'block';}}}</script></head><body><div id="div1"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">11111</div><div>22222</div><div>33333</div></div></body></html>
普通方法变型
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象的选项卡</title><style>#div1 div { width: 200px; height: 200px; border: 1px solid #000; display: none; }.active { background: red; }</style><script>var oParent = null;var aInput = null;var aDiv = null;window.onload = function(){oParent = document.getElementById('div1');aInput = oParent.getElementsByTagName('input');aDiv = oParent.getElementsByTagName('div');init();};function init(){ //初始化的函数方法for(var i=0; i<aInput.length; i++){aInput[i].index = i;aInput[i].onclick = change;}}function change(){for(var i=0; i<aInput.length; i++){aInput[i].className = '';aDiv[i].style.display = 'none';}this.className = 'active';aDiv[this.index].style.display = 'block';}/*- 普通方法变型- 尽量不要出现函数嵌套函数- 可以有全局变量- 把onload中不是赋值的语句放到单独的函数中*/</script></head><body><div id="div1"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">11111</div><div>22222</div><div>33333</div></div></body></html>
关于this的指向
oDiv.onclick = function(){this: oDiv};---oDiv.onclick = show;function show(){this: oDiv}---oDiv.onclick = function(){show();};function show(){this: window}
改写成面向对象
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象bianxie</title><style>#div1 div { width: 200px; height: 200px; border: 1px solid #000; display: none; }.active { background: red; }</style><script>var oParent = null;var aInput = null;var aDiv = null;window.onload = function(){var t1 = new Tab();t1.init();};function Tab(){this.oParent = document.getElementById('div1');this.aInput = this.oParent.getElementsByTagName('input');this.aDiv = this.oParent.getElementsByTagName('div');}Tab.prototype.init = function(){var This = this;for(var i=0; i<this.aInput.length; i++){this.aInput[i].index = i;this.aInput[i].onclick = function(){This.change(this);};}}Tab.prototype.change = function(obj){for(var i=0; i<this.aInput.length; i++){this.aInput[i].className = '';this.aDiv[i].style.display = 'none';}obj.className = 'active';this.aDiv[obj.index].style.display = 'block';}/*- 改成面向对象- 全局变量就是属性- 函数就是方法- onload中创建对象- 改this指向问题:注意事件或者是定时器里面的this。要尽量保持面向对象中的this指向对象*/</script></head><body><div id="div1"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">11111</div><div>22222</div><div>33333</div></div></body></html>
面向对象的复用
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象bianxie</title><style>#div1 div, #div2 div { width: 200px; height: 200px; border: 1px solid #000; display: none; }.active { background: red; }</style><script>var oParent = null;var aInput = null;var aDiv = null;window.onload = function(){var t1 = new Tab('div1');t1.init();var t2 = new Tab('div2');t2.init();t2.autoplay();};function Tab(id){this.oParent = document.getElementById(id);this.aInput = this.oParent.getElementsByTagName('input');this.aDiv = this.oParent.getElementsByTagName('div');this.iNow = 0;}Tab.prototype.init = function(){var This = this;for(var i=0; i<this.aInput.length; i++){this.aInput[i].index = i;this.aInput[i].onclick = function(){This.change(this);};}}Tab.prototype.change = function(obj){for(var i=0; i<this.aInput.length; i++){this.aInput[i].className = '';this.aDiv[i].style.display = 'none';}obj.className = 'active';this.aDiv[obj.index].style.display = 'block';}Tab.prototype.autoplay = function(){var This = this;setInterval(function(){if(This.iNow == This.aInput.length - 1){This.iNow = 0;} else {This.iNow ++;}for(var i=0; i<This.aInput.length; i++){This.aInput[i].className = '';This.aDiv[i].style.display = 'none';}This.aInput[This.iNow].className = 'active';This.aDiv[This.iNow].style.display = 'block';}, 2000)}</script></head><body><div id="div1"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">11111</div><div>22222</div><div>33333</div></div><div id="div2"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">11111</div><div>22222</div><div>33333</div></div></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象编写拖拽</title><style>#div1 { width: 100px; height: 100px; background: red; position: absolute; }</style><script>/* 普通拖拽window.onload = function(){var oDiv = document.getElementById('div1');var disX = 0;var disY = 0;oDiv.onmousedown = function(ev){var ev = ev || window.event;disX = ev.clientX - oDiv.offsetLeft;disY = ev.clientY - oDiv.offsetTop;document.onmousemove = function(ev){var ev = ev || window.event;oDiv.style.left = ev.clientX - disX + 'px';oDiv.style.top = ev.clientY - disY + 'px';}document.onmouseup = function(){document.onmousemove = null;document.onmouseup = null;}return false;}}*//* 第一步:普通方法变型//先变型var oDiv = null;var disX = 0;var disY = 0;window.onload = function(){oDiv = document.getElementById('div1');init();}function init(){oDiv.onmousedown = fnDown;}function fnDown(ev){var ev = ev || window.event;disX = ev.clientX - oDiv.offsetLeft;disY = ev.clientY - oDiv.offsetTop;document.onmousemove = fnMove;document.onmouseup = fnUp;return false;}function fnMove(ev){var ev = ev || window.event;oDiv.style.left = ev.clientX - disX + 'px';oDiv.style.top = ev.clientY - disY + 'px';}function fnUp(){document.onmousemove = null;document.onmouseup = null;}*///改成面向对象window.onload = function(){var d1 = new Drag('div1');d1.init();}function Drag(id){this.oDiv = document.getElementById(id);this.disX = 0;this.dixY = 0;}Drag.prototype.init = function(){var This = this;this.oDiv.onmousedown = function(ev){var ev = ev || window.event;This.fnDown(ev);return false;};}Drag.prototype.fnDown = function(ev) {var ev = ev || window.event;var This = this;this.disX = ev.clientX - this.oDiv.offsetLeft;this.disY = ev.clientY - this.oDiv.offsetTop;document.onmousemove = function(ev){var ev = ev || window.event;This.fnMove(ev);};document.onmouseup = this.fnUp;}Drag.prototype.fnMove = function(ev){this.oDiv.style.left = ev.clientX - this.disX + 'px';this.oDiv.style.top = ev.clientY - this.disY + 'px';}Drag.prototype.fnUp = function(){document.onmousemove = null;document.onmouseup = null;}</script></head><body><div id="div1"></div></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style></style><script>/*function Aaa(){this.name='小明';}Aaa.prototype.showName=function(){alert(this.name);}var a1 = new Aaa();a1.showName();var arr = new Array();arr.push();arr.sort();// 在js源码中:系统对象也是基于原型的程序function Array(){this.length = 0;}Array.prototype.push = function(){};Array.prototype.sort = function(){};*///尽量不要去修改或添加系统对象下面的方法和属性var arr = [1, 2, 3];//Arr.prototype.push = function(){}; //加上这句话,就修改了源码中的push方法,那么后面那一句中的4、5、6就添加不进去了Array.prototype.push = function(){ //自己写一个数组的push方法//this : 1, 2, 3//arguments: 4, 5, 6for(var i=0; i<arguments.length; i++){this[this.length] = arguments[i];}return this.length;}arr.push(4, 5, 6);alert(arr);</script></head><body></body></html>
给基本类型添加方法
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style></style><script>/*var str = 'hello';alert( typeof str); //stringstr.charAt(0); //字符串为什么下面会有方法呢?str.indexOf('e');*///包装对象:基本类型都有自己对应的包装对象(String, Number, Boolean)(null和undefined没有包装对象)/*var str = new String('hello');alert(typeof str); //objectalert(str.charAt(1)); //弹出eString.prototype.charAt = function(){}; //基本类型的方法都是放在它们的包装对象上*//*var str = 'hello'; //str是字符串str.charAt(0); //基本类型找到对应的包装对象类型,然后包装对象把所有的属性和方法给了基本类型,然后包装对象消失*///给基本类型添加对象的时候,就是把方法添加到基本类型对应的包装对象下面var str = 'hello';String.prototype.lastValue = function(){return this.charAt(this.length-1);};alert(str.lastValue()); //ovar str1 = 'hello';str1.number = 10; //在str1的包装对象上创建了一个number,然后包装对象就消失了alert(str1.number); //undefined 再去调用这句话的时候,此时又重新创建了一个对象,这个对象与刚才那个对象不是同一个</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象中的原型链</title><style></style><script>//原型链:实例对象与原型之间的连接叫作原型链//_proto_ (隐式连接)//原型链的最外层是Object.prototypefunction Aaa(){}Aaa.prototype.num = 10;var a1 = new Aaa();alert(a1.num); //10 a1现在它自己下面找,找不到这个num,然后又通过原型链到了Aaa.prototype,到它下面去找,最终找到了numfunction Bbb(){this.num = 20;}Bbb.prototype.num = 10;var b1 = new Bbb();alert(b1.num); //20 简单来讲,实例上的方法的优先级高于原型上的方法;本质上来讲,是从b1下面找num直接就找到了,于是就不需要再进一步通过原型链去找到Bbb.prototype上的num了。function Ccc(){};var c1 = new Ccc();Object.prototype.num = 30; //弹出30 c1下找不到num;顺着原型链找到Ccc也找不到num,继续顺着原型链往上找,找到Object.prototype,找到了numalert(c1.num);</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象中的原型链</title><style></style><script>//hasOwnProperty: 看是不是对象自身下面的属性var arr = [];arr.num = 10;Array.prototype.num2 = 20;alert(arr.hasOwnProperty('num')); //truealert(arr.hasOwnProperty('num2')); //falsealert(arr.hasOwnProperty == Object.prototype.hasOwnProperty); //true hasOwnProperty其实是Object.prototype下面的方法</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象中的原型链</title><style></style><script>//constructor: 查看对象的构造函数function Aaa(){}var a1 = new Aaa();alert(a1.constructor); //function Aaavar arr = [];alert(arr.constructor == Array); //true/*在写完一个构造函数之后function Aaa(){}程序会自动添加一句话:Aaa.prototype.constructor = Aaa; //每一个函数都会有的,都是自动生成的这时候new一个Aaavar a1 = new Aaa();alert(a1.constructor); //弹出Aaa如果手动写一句:Aaa.prototype.constructor = Array;那么再去弹a1.constructor的话,弹出的就是Array了。而hasOwnProperty这个属性是添加在Object.prototype下面的,所以每个对象下面去查这个hasOwnProperty也都会有。但是hasOwnProperty这个方法不是在具体对象下面的,而都是沿着原型链找到Object.prototype身上找到的。跟constructor是不一样的。*/function Bbb(){}Bbb.prototype.name = '小明';Bbb.prototype.age = 20;var b1 = new Bbb();alert(b1.constructor); //function Bbb()//下面这种写法就无意识地改变了c1的constructor,因为json直接赋值给了Ccc.prototype,而不是向上面那段代码是添加操作。那么原本系统自动生成的那句话Ccc.prototype.constructor = Ccc这句话就被覆盖掉了。然后通过c1.constructor去找的话,其实找的就是这个json所对应的constructor了。function Ccc(){}Ccc.prototype = {name: '小明',age: 20}var c1 = new Ccc();alert(c1.constructor); //function Object//为了避免上述问题,应该注意,用json简写的时候,要把constructor修正过来,如下:function Ddd(){}Ddd.prototype = {constructor: Ddd, //通过这一句来修正一下name: '小明',age: 20}var d1 = new Ddd();alert(d1.constructor); //Ddd</script></head><body></body></html>
for in循环,有些属性找不到
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>面向对象中的原型链</title><style></style><script>function Aaa(){}Aaa.prototype.name = 10;Aaa.prototype.constructor = Aaa;for (var attr in Aaa.prototype){alert(attr); //只能找到自己添加的,系统自动生成的比如constructor,for in循环是找不到的}</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>instanceof()</title><style></style><script>// instanceof: 对象与构造函数在原型链上是否有关系function Aaa(){}var a1 = new Aaa();alert(a1 instanceof Aaa); //true 看a1是否与Aaa在同一个原型链上alert(a1 instanceof Array); //falsealert(a1 instanceof Object); //true</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>toString()</title><style></style><script>// toString():// 位置:系统对象下面都是自带的;自己写的对象都是通过原型链找Object下面的// 作用:把对象转成字符串var arr = [];alert(arr.toString); //找得到alert(arr.toString == Object.prototype.toString); //false 系统对象下面的toString不在Object原型上function Aaa(){}var a1 = new Aaa();alert(a1.toString); //找得到alert(a1.toString == Object.prototype.toString); //true 构造函数生成的对象的toString方法在Object原型上var arr = [1, 2, 3];alert(typeof arr.toString()); //stringalert(arr.toString()); //"1, 2, 3"//因为知道toString在哪儿了,所以可以手动修改toString方法Array.prototype.toString = function(){return this.join('+');}alert(arr.toString()); //"1+2+3"var num = 255;alert(num.toString(16)); //"ff" 将255转成16进制//利用toString进行类型判断(用constructor和instanceof也都可以进行类型判断)。推荐toString来判断例如数组的类型var arr = []var date = new Date;var json = {}var reg = new RegExp;var n = null;alert(Object.prototype.toString.call(arr)); //[object Array]alert(Object.prototype.toString.call(date)); //[object Date]alert(Object.prototype.toString.call(json)); //[object Object]alert(Object.prototype.toString.call(reg)); //[object RegExp]alert(Object.prototype.toString.call(n)); //[object Null]//判断类型时直接进行比较就可以了,例如判断arr是否是数组:alert(Object.prototype.toString.call(arr) == '[object Array]'); //true//举例说明用instanceof和constructor来判断数组失效,但是toString依然有效的例子window.onload = function(){var oF = document.createElement('iframe');document.body.appendChild(oF);var ifArray = window.frames[0].Array; //ifArray就是iframe里面的数组var arr = new ifArray(); //ifArray就是iframe里面的数组 这时候跨页面了alert(arr.constructor == Array); //false constructor判断iframe下面的数组失效alert(arr instanceof Array); //false 判断失效alert(Object.prototype.toString.call(arr) == '[object Array]'); //true 判断依然有效}</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>继承</title><style></style><script>// 继承:子类不影响父类;子类可以继承父类的一些功能(实现代码复用)function CreatePerson(name, sex){ //父类this.name = name;this.sex = sex;}CreatePerson.prototype.showName = function(){alert(this.name);}var p1 = new CreatePerson('小明', '男');p1.showName();//属性的继承:调用父类的构造函数 用call改this指向//方法的继承:用for in循环function CreateStar(name, sex, job){ //子类// this.name = name;// this.sex = sex;CreatePerson.call(this, name, sex); //调用父类构造函数 需要修改指向this.job = job;}/*CreateStar.prototype = CreatePerson.prototype; //将父类的原型赋给子类,那么子类就获得了父类下所有的属性值,实现了方法的继承 但是这里有对象的引用问题,造成互相干涉例如:CreateStar.prototype.showJob = function(){}上面子类的原型添加的方法,那么父类CreatePerson.prototype下面也有了showJob的方法*///方法的继承应该用for in循环,将父类的所有属性拷贝给子类,这叫作“拷贝继承”。jQuery也是采用拷贝继承extendfunction extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}extend(CreateStar.prototype, CreatePerson.prototype )var p2 = new CreateStar('黄晓明', '男', '演员')p2.showName();</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>继承</title><style></style><script>var a = {name: '小明'};//var b = a;// var b = {};// for(var attr in a){// b[attr] = a[attr];// }// b.name = "小强";// alert(a.name);//将对象属性的拷贝封装成一个函数function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}var b = {};extend(b, a);b.name = '小强';alert(b.name);alert(a.name);</script></head><body></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>继承</title><style></style><script>var a = [1, 2, 3];var b = a;// b.push(4); //修改 a、b之间引用链条存在// alert(a); //1, 2, 3, 4 a被b影响了b = [1, 2, 3, 4]; //重新赋值,内存中这个b又重新生成了。a和b之间这个引用的链条已经断开,a、b没有关系alert(a); //1, 2, 3 a未被影响//在for in循环中,子类原型的方法也直接等于了父类原型的方法,因为方法是函数,也是个对象,为什么这种“对象 = 对象”没有互相干涉呢?这是因为函数有些特殊,不能被修改,只能被重新赋值</script></head><body></body></html>
继承的拖拽
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>#div1 {width: 100px; height: 100px; background: red; position: absolute;}#div2 {width: 100px; height: 100px; background: yellow; position: absolute; left: 100px;}</style><script src="jquery-1.11.1.js"></script><script>window.onload = function(){var d1 = new Drag('div1');d1.init();var d2 = new ChildDrag('div2');d2.init();}//父类的面向对象的拖拽开始function Drag(id){ //父类this.obj = document.getElementById(id);this.disX = 0;this.disY = 0;}Drag.prototype.init = function(){var This = this;this.obj.onmousedown = function(ev){var ev = ev || window.event;This.fnDown(ev);document.onmousemove = function(ev){var ev = ev || window.event;This.fnMove(ev);}document.onmouseup = function(){This.fnUp();}return false;}}Drag.prototype.fnDown = function(ev){this.disX = ev.clientX - this.obj.offsetLeft;this.disY = ev.clientY - this.obj.offsetTop;}Drag.prototype.fnMove = function(ev){this.obj.style.left = ev.clientX - this.disX + 'px';this.obj.style.top = ev.clientY - this.disY + 'px';}Drag.prototype.fnUp = function(){document.onmousemove = null;document.onmouseup = null;}//父类的面向对象的拖拽结束//子类继承父类开始function ChildDrag(id){ //子类Drag.call(this, id);}extend(ChildDrag.prototype, Drag.prototype);//通过改变ChildDrap原型下的fnMove,给子类添加了限制拖拽时,元素超出可视区左右边界的功能ChildDrag.prototype.fnMove = function(ev){var L = ev.clientX - this.disX;var T = ev.clientY - this.disY;if(L < 0){L = 0;} else if (L > document.documentElement.clientWidth - this.obj.offsetWidth){L = document.documentElement.clientWidth - this.obj.offsetWidth;}this.obj.style.left = L + 'px';this.obj.style.top = T + 'px';}function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}//子类继承父类结束</script></head><body><div id="div1"></div><div id="div2"></div></body></html>
类式继承
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style></style><script>//类:JS是没有类的概念的,可以把JS中的构造函数看做是类//要做属性和方法继承的时候,要分开继承function Aaa(){ //父类this.name = '小明';this.arr = [1, 2, 3];}Aaa.prototype.showName = function(){alert(this.name);}function Bbb(){ //子类}Bbb.prototype = new Aaa(); //这句话就是类式继承//只写上面一句话是有问题的,修改了constructor指向。//Bbb.prototype.constructor = Bbb; //修正指向问题var b1 = new Bbb();b1.showName();alert(b1.name);alert(b1.constructor); //弹出的并不是Bbb,而是Aaa。只有写了上面修正指向的那句话,这里才会变成Bbb//真正规范的类式继承要用下面几句话:// function Bbb(){ //这里只继承了属性// Aaa.call(this)// }//var F = function(){}; //创建一个空的构造函数//F.prototype = Aaa.prototype;//Bbb.prototype = new F(); //这里只继承了方法//Bbb.prototype.constructor = Bbb;b1.arr.push(4);var b2 = new Bbb();alert(b2.arr); //[1, 2, 3, 4] 这里看到上面的b1.arr.push(4)影响到了这里 要避免这种问题,应该用上面的类式继承的规范写法才行</script></head><body></body></html>
原型继承
<head><meta charset="UTF-8"><title>原型继承</title><style></style><script>var a = {name: '小明'}var b = cloneObj(a); //让b继承ab.name = '小强'; //这一句不会更改a的name,因为这一句在b的下面又新建了一个属性name,值为“小强”alert(b.name); //小强alert(a.name); //小明function cloneObj(obj){var F = function(){};F.prototype = obj;return new F();}</script></head><body></body></html>
对象的多种表现形式
什么是组件?
创建自定义事件
例子:基于JQ的选项卡的组件开发模式
本课练习
如何配置参数和默认参数
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>组件开发中的参数问题</title><script>//用json来解决参数数量问题function show(opt){}show({id: 'div1',toDown: function(){},toUp: function(){}});//用下面的方法解决参数顺序问题var a = { //配置参数//name: '小明'name: '小明'}var b = { //默认参数name: '小强'}extend(b, a); //当有配置的时候,走配置,没有配置的时候,走默认alert(b.name);function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}</script></head><body></body></html>
拖拽的组件开发
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>#div1 {width: 100px; height: 100px; background: red; position: absolute;}#div2 {width: 100px; height: 100px; background: yellow; position: absolute; left: 100px;}#div3 {width: 100px; height: 100px; background: blue; position: absolute; left: 200px;}#div4 {width: 100px; height: 100px; background: green; position: absolute; left: 300px;}</style><script src="jquery-1.11.1.js"></script><script>/*组件开发:像兄弟之间的关系(代码复用的一种形式)*/window.onload = function(){var d1 = new Drag();d1.init('div1');var d2 = new Drag();d2.init('div2', { //配置参数toDown: function(){document.title = 'hello';}});var d3 = new Drag();d3.init('div3', { //配置参数toDown: function(){document.title = '妙味';},toUp: function(){document.title = '课堂';}});var d4 = new Drag();d4.init('div4', { //配置参数toUp: function(){document.title = 'byebye';}});}function Drag(){this.obj = null;this.disX = 0;this.disY = 0;this.settings = { //默认参数//id不应该属于配置参数当中,它属于必填项toDown: function(){},toUp: function(){}}}Drag.prototype.init = function(id, opt){var This = this;this.obj = document.getElementById(id);extend(this.settings, opt); //用配置覆盖默认this.obj.onmousedown = function(ev){var ev = ev || window.event;This.fnDown(ev);This.settings.toDown();document.onmousemove = function(ev){var ev = ev || window.event;This.fnMove(ev);}document.onmouseup = function(){This.fnUp();This.settings.toUp();}return false;}}Drag.prototype.fnDown = function(ev){this.disX = ev.clientX - this.obj.offsetLeft;this.disY = ev.clientY - this.obj.offsetTop;}Drag.prototype.fnMove = function(ev){this.obj.style.left = ev.clientX - this.disX + 'px';this.obj.style.top = ev.clientY - this.disY + 'px';}Drag.prototype.fnUp = function(){document.onmousemove = null;document.onmouseup = null;}function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}</script></head><body><div id="div1"></div> <!-- 红色方块是老大 --><div id="div2"></div> <!-- 黄色方块是老二 黄色的按下之后title有一个变化 --><div id="div3"></div> <!-- 老三 按下title变化,抬起title变化 --><div id="div4"></div> <!-- 老四 鼠标抬起时title有变化 --></body></html>
弹窗的组件开发
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>弹窗的组件开发</title><style>* {margin : 0; padding; 0}.login {background: white; border: 1px #000 solid; position: absolute; left: 0; top: 0; z-index: 2;}.title {height: 30px; background: gray; color: white;}.title .close {float: right;}#mask {width: 500px; height: 500px; background: black; filter: alpha(oapcity=50); opacity: 0.5; position: absolute; left: 0; top: 0; z-index: 1;}</style><script>window.onload = function(){var aInput = document.getElementsByTagName('input');aInput[0].onclick = function(){var d1 = new Dialog();d1.init({//配置参数iNow: 0,title: '登陆'});}aInput[1].onclick = function(){var d2 = new Dialog();d2.init({//配置参数iNow: 1,w : 100,h : 400,dir: 'right',title: '公告'});}aInput[2].onclick = function(){var d3 = new Dialog();d3.init({//配置参数iNow: 2,mask: true});}}function Dialog(){this.oLogin = null;this.settings = { //默认参数w: 300,h: 300,dir: 'center',title: '',mask: false}}Dialog.prototype.json = {}; //防止添加多个弹窗Dialog.prototype.init = function(opt){extend(this.settings, opt);if(this.json[opt.iNow] == undefined){this.json[opt.iNow] = true;}if(this.json[opt.iNow]){ //防止添加多个弹窗this.create();this.fnClose();if(this.settings.mask){this.createMask();}this.json[opt.iNow] = false;}}Dialog.prototype.create = function(){this.oLogin = document.createElement('div');this.oLogin.className = 'login';this.oLogin.innerHTML = '<div class="title"><span>' + this.settings.title + '</span><span class="close">X</span></div><div class="content"></div>';document.body.appendChild(this.oLogin);this.setData();}Dialog.prototype.setData = function(){this.oLogin.style.width = this.settings.w + 'px';this.oLogin.style.height = this.settings.h + 'px';if(this.settings.dir == 'center'){this.oLogin.style.left = (viewWidth() - this.oLogin.offsetWidth)/2 + 'px';this.oLogin.style.top = (viewHeight() - this.oLogin.offsetHeight)/2 + 'px';} else if (this.settings.dir == 'right'){this.oLogin.style.left = (viewWidth() - this.oLogin.offsetWidth) + 'px';this.oLogin.style.top = (viewHeight() - this.oLogin.offsetHeight) + 'px';}}Dialog.prototype.fnClose = function(){var oClose = this.oLogin.getElementsByTagName('span')[1];var This = this;oClose.onclick = function(){document.body.removeChild(This.oLogin);if(This.settings.mask){document.body.removeChild(This.oMask);}This.json[This.settings.iNow] = true;}}Dialog.prototype.createMask = function(){var oMask = document.createElement('div');oMask.id = 'mask';document.body.appendChild(oMask);this.oMask = oMask;oMask.style.width = viewWidth() + 'px';oMask.style.height = viewHeight() + 'px';}function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}function viewWidth(){return document.documentElement.clientWidth;}function viewHeight(){return document.documentElement.clientHeight;}</script></head><body><input type="button" value="1"><input type="button" value="2"><input type="button" value="3"><!-- <div class="login"><div class="title"><span>标题</span><span class="close">X</span></div><div class="content"></div></div> --><!-- <div id="mask"></div> --></body></html>
理解自定义事件
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>自定义事件</title><script>// 自定义事件:主要是跟函数有关系,让函数能够具备事件的某些特性// 三个人都针对show来添加功能。都添加到一个地方会乱,于是三个人分开来写/*function show(){alert(1); //第一个人写}function show(){alert(2); //第二个人写}function show(){alert(3); //第三个人写}show(); //只能执行第三个人写的,因为函数不能修改只能覆盖*///看看是否能让函数具备事件的特性,多人写的可以绑定上去,就解决了多人协作的问题。原理就如以下情形。当然以下代码不是添加自定义事件的代码,只是为了方便理解:/*window.addEventListener('show', function(){alert(1); //第一个人写的}, false);window.addEventListener('show', function(){alert(2); //第二个人写的}, false);window.addEventListener('show', function(){alert(3); //第三个人写的}, false);show(); //主动触发自定义事件*/</script></head><body></body></html>
用原生js实现自定义事件
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>自定义事件</title><script>//自定义事件重点在于将函数和元素以及事件名称建立关系,在执行某个函数的时候,主动触发某个事件名称下面相关的所有函数window.onload = function(){var oDiv = document.getElementById('div1');var oSpan = document.getElementById('span1');bindEvent(oDiv, 'click', function(){alert(1);})bindEvent(oDiv, 'click', function(){alert(2);})bindEvent(oSpan, 'show', function(){ //这里的show就是个自定义事件alert(3);})bindEvent(oSpan, 'show', function(){ //这里的show就是个自定义事件alert(4);})bindEvent(oSpan, 'hide', function(){ //这里的show就是个自定义事件alert(5);})fireEvent(oSpan, 'show'); //主动触发,弹出3, 4fireEvent(oDiv, 'click'); //主动触发,弹出1, 2}function bindEvent(obj, events, fn){//fn: 看作一本书 《西游记》//obj: 相当于图书馆的楼层 文学楼//events: 相当于书架 古典文学书架obj.listeners = obj.listeners || {}; //先找到楼层,没有楼层就创建楼层obj.listeners[events] = obj.listeners[events] || []; //再找到书架,没有书架就创建书架obj.listeners[events].push(fn); //把fn这本书放到书架上/* 通过以上的方式,将obj,events和fn建立了关系*/if(obj.addEventListener){obj.addEventListener(events, fn, false);} else {obj.attachEvent('on' + events, fn);}}function fireEvent(obj, events){ //主动触发自定义事件for(var i=0; i<obj.listeners[events].length; i++){obj.listeners[events][i]();}}</script></head><body><div id="div1">div</div><span id="span1">span</span></body></html>
配置、方法、自定义事件分离——正规组件的写法——基于拖拽的组件进行的修改
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>自定义事件的拖拽组件</title><style>#div1 {width: 100px; height: 100px; background: red; position: absolute;}#div2 {width: 100px; height: 100px; background: yellow; position: absolute; left: 100px;}#div3 {width: 100px; height: 100px; background: blue; position: absolute; left: 200px;}#div4 {width: 100px; height: 100px; background: green; position: absolute; left: 300px;}</style><script src="jquery-1.11.1.js"></script><script>window.onload = function(){var d1 = new Drag();d1.init('div1');var d2 = new Drag();d2.init('div2');bindEvent(d2, 'toDown', function(){document.title = 'hello';});bindEvent(d2, 'toDown', function(){ //新来的一个同事扩展d2的toDown事件的时候,更容易document.body.style.background = 'black';})var d3 = new Drag();d3.init('div3');bindEvent(d3, 'toDown', function(){document.title = '妙味';})bindEvent(d3, 'toUp', function(){document.title = '课堂';})var d4 = new Drag();d4.init('div4');bindEvent(d4, 'toUp', function(){document.title = 'byebye';})}function Drag(){this.obj = null;this.disX = 0;this.disY = 0;this.settings = {}}Drag.prototype.init = function(id, opt){var This = this;this.obj = document.getElementById(id);extend(this.settings, opt);this.obj.onmousedown = function(ev){var ev = ev || window.event;This.fnDown(ev);fireEvent(This, 'toDown');document.onmousemove = function(ev){var ev = ev || window.event;This.fnMove(ev);}document.onmouseup = function(){This.fnUp();fireEvent(This, 'toUp');}return false;}}Drag.prototype.fnDown = function(ev){this.disX = ev.clientX - this.obj.offsetLeft;this.disY = ev.clientY - this.obj.offsetTop;}Drag.prototype.fnMove = function(ev){this.obj.style.left = ev.clientX - this.disX + 'px';this.obj.style.top = ev.clientY - this.disY + 'px';}Drag.prototype.fnUp = function(){document.onmousemove = null;document.onmouseup = null;}function extend(obj1, obj2){for(var attr in obj2){obj1[attr] = obj2[attr];}}function bindEvent(obj, events, fn){obj.listeners = obj.listeners || {};obj.listeners[events] = obj.listeners[events] || [];obj.listeners[events].push(fn);if(obj.nodeType){ //如果传进来的是DOM元素的话,走着下面;如果传进来的不是DOM,是对象的话,就不走下面,只走上面了if(obj.addEventListener){obj.addEventListener(events, fn, false);} else {obj.attachEvent('on' + events, fn);}}}function fireEvent(obj, events){if(obj.listeners && obj.listeners[events]){for(var i=0; i<obj.listeners[events].length; i++){obj.listeners[events][i]();}}}</script></head><body><div id="div1"></div><div id="div2"></div><div id="div3"></div><div id="div4"></div></body></html>
**用JQ实现选项卡的组件开发
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>基于JQ的选项卡组件开发</title><style>html, body {margin: 0; padding: 0;}#div1 div, #div2 div, #div3 div, #div4 div {width: 200px; height: 200px; border: 1px solid #000; display: none;}#div1 .active, #div2 .active, #div3 .active, #div4 .active {background: red;}</style><script src="jquery-1.11.1.js"></script><script>/*title: 基于JQ的选项卡组件Options:- event- delayMethods:- nowSel() - 设置开始的tab数- getContent() - 获取当前内容Events:- beforeClick 点击前触发- afterClick 点击后触发*/// JQ中的主动触发:trigger()$(function(){var t1 = new Tab();t1.init('div1', {});var t2 = new Tab();t2.init('div2', {event: 'mouseover'});var t3 = new Tab();t3.init('div3', {event: 'mouseover',delay: 200});var t4 = new Tab();t4.init('div4', {});t4.nowSel(2);$('#input1').click(function(){alert(t4.getContent());})$(t4).on('beforeClick', function(){alert(t4.getContent());})$(t4).on('afterClick', function(){alert(t4.getContent());})})function Tab(){this.oParent = null;this.aInput = null;this.aDiv = null;this.iNow = 0;this.settings = { //默认参数event: 'click',delay: 0}}Tab.prototype.init = function(oParent, opt){$.extend(this.settings, opt);this.oParent = $('#' + oParent);this.aInput = this.oParent.find('input');this.aDiv = this.oParent.find('div');this.change();}Tab.prototype.change = function(){var This = this;var timer = null;this.aInput.on(this.settings.event, function(){if(This.settings.event == 'mouseover' && This.settings.delay){var _this = this;timer = setTimeout(function(){show(_this);}, This.settings.delay)} else {show(this);}}).mouseout(function(){clearTimeout(timer);});function show(obj){$(This).trigger('beforeClick');This.aInput.attr('class', '');This.aDiv.css('display', 'none');$(obj).attr('class', 'active');This.aDiv.eq($(obj).index()).css('display', 'block');This.iNow = $(obj).index();$(This).trigger('afterClick');}Tab.prototype.nowSel = function(index){this.aInput.attr('class', '');this.aDiv.css('display', 'none');this.aInput.eq(index).attr('class', 'active');this.aDiv.eq(index).css('display', 'block');this.iNow = index;}Tab.prototype.getContent = function(){return this.aDiv.eq(this.iNow).html();}}</script></head><body><div id="div1"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">111111</div><div>222222</div><div>333333</div></div><div id="div2"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">111111</div><div>222222</div><div>333333</div></div><div id="div3"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">111111</div><div>222222</div><div>333333</div></div><div id="div4"><input type="button" value="1" class="active"><input type="button" value="2"><input type="button" value="3"><div style="display: block">111111</div><div>222222</div><div>333333</div></div><input type="button" value="点击" id="input1"></body></html>
子集影响父级的bug
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>#div1 {width: 200px; height: 200px; background: red;}#div2 {width: 100px; height: 100px; background: yellow;}</style><script>window.onload = function(){var oDiv = document.getElementById('div1');oDiv.onmouseover = function(){document.title += '1';}oDiv.onmouseout = function(){document.title += '2';}// 会发现鼠标移到黄色div上的时候,title部分会一下子出现21,这个2是从div1移到div2触发的,而1是通过div2冒泡到div1上触发的}</script></head><body><div id="div1"><div id="div2"></div></div></body></html>
上述问题的解决方式(1)
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>#div1 {width: 200px; height: 200px; background: red;}#div2 {width: 100px; height: 100px; background: yellow;}</style><script>// 解决方案:// 1. js: 用onmouseener和onmouseleave事件替代onmouseover和onmouseout。onmouseenter和onmouseleave事件,子级不会影响到父级// 2. csswindow.onload = function(){var oDiv = document.getElementById('div1');oDiv.onmouseenter = function(){document.title += '1';}oDiv.onmouseleave = function(){document.title += '2';}}</script></head><body><div id="div1"><div id="div2"></div></div></body></html>
上述问题的解决方式(2)
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>#div1 {width: 200px; height: 200px; background: red;}#div2 {width: 100px; height: 100px; background: yellow;}</style><script>// 解决方案:// 1. js: 用onmouseener和onmouseleave事件替代onmouseover和onmouseout。onmouseenter和onmouseleave事件,子级不会影响到父级// 上述两个事件有兼容性问题,但是兼容性问题不大,而且做兼容非常的麻烦 兼容方式如下:// 2. csswindow.onload = function(){var oDiv = document.getElementById('div1');oDiv.onmouseover = function(ev){var ev = ev || window.event;var a = this, b = ev.relatedTarget; //ev.relatedTarget是相对目标,可以理解为之前的目标/*1. 从body移到div1:a - div1;b - body2. 从div1移到div2:a - div1;b - div13. 从div2移到div1:a - div1;b - div2*/if(!elContains(a, b) && a!=b){document.title += '1';}}oDiv.onmouseout = function(ev){var ev = ev || window.event;var a = this, b = ev.relatedTarget;if(!elContains(a, b) && a!=b){document.title += '2';}}}function elContains(a, b){ //判断两个元素是否是嵌套关系,看a是否包含breturn a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);}</script></head><body><div id="div1"><div id="div2"></div></div></body></html>
图片的放大镜效果
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>图片放大镜效果</title><style>html, body {margin: 0; padding: 0;}#div1 {width: 180px; height: 180px; overflow: hidden; position: relative;}#div1 span {width: 100px; height: 100px; background: yellow; opacity: 0.5; filter: alpha(opacity=50); position: absolute; left: 0; top: 0; display: none;}#mask {width: 180px; height: 180px; background: red; position: absolute; left: 0; top: 0; opacity: 0; filter: alpha(oapcity=0);}#div2 {width: 500px; height: 500px; position: absolute; left: 250px; top: 50px; overflow: hidden;}#div2 img {position: absolute; left: 0; top: 0;}</style><script>//这里的onmouseover和onmouseout是用过CSS方式解决的问题,方法是添加了一个透明的层window.onload = function(){var oDiv = document.getElementById('div1');var oSpan = oDiv.getElementsByTagName('span')[0];var oDiv2 = document.getElementById('div2');var img2 = oDiv2.getElementsByTagName('img')[0];oDiv.onmouseenter = function(){oSpan.style.display = 'block';}oDiv.onmouseleave = function(){oSpan.style.display = 'none';}oDiv.onmousemove = function(ev){var ev = ev || window.event;var L = ev.clientX - oDiv.offsetLeft - oSpan.offsetWidth / 2;var T = ev.clientY - oDiv.offsetTop - oSpan.offsetHeight / 2;if(L < 0){L = 0;} else if (L > oDiv.offsetWidth - oSpan.offsetWidth){L = oDiv.offsetWidth - oSpan.offsetWidth;}if(T < 0){T = 0;} else if (T > oDiv.offsetHeight - oSpan.offsetHeight){T = oDiv.offsetHeight - oSpan.offsetHeight;}oSpan.style.left = L + 'px';oSpan.style.top = T + 'px';var scaleX = L / (oDiv.offsetWidth - oSpan.offsetWidth);var scaleY = T / (oDiv.offsetHeight - oSpan.offsetHeight);img2.style.left = -scaleX * (img2.offsetWidth - oDiv2.offsetWidth) + 'px';img2.style.top = -scaleY * (img2.offsetHeight - oDiv2.offsetHeight) + 'px';}}</script></head><body><div id="div1"><img src="b2.jpg"><span></span><div id="mask"></div></div><div id="div2"><img src="b1.jpg"></div></body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>苹果菜单</title><script>// Math.pow(3, 2); //3的平方// Math.pow(2, 3); //2的立方// Math.sqrt(9); //9的开方// Math.pow(9, 1/3); //9的开立方</script><style>html, body {margin: 0; padding: 0;}#div1 img {width: 64px;}#div1 {width: 100%; height: auto; position: absolute; bottom: 0; text-align: center;}input {width: 300px;}</style><script>window.onload = function(){var aInput = document.getElementsByTagName('input');var oDiv= document.getElementById('div1');var aImg = oDiv.getElementsByTagName('img');document.onmousemove = function(ev){var ev = ev || window.event;for(var i=0; i<aImg.length; i++){var x = aImg[i].offsetLeft + aImg[i].offsetWidth/2;var y = aImg[i].offsetTop + aImg[i].offsetHeight/2 + oDiv.offsetTop;var a = ev.clientX - x;var b = ev.clientY - y;var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));var scale = 1 - c/300;if(scale < 0.5){scale = 0.5;}aInput[i].value = 'x轴:' + x + ',Y轴:' + y + ',与鼠标距离:' + c;aImg[i].style.width = scale * 128 + 'px';aImg[i].style.height = scale * 128 + 'px';}}}</script></head><body><input type="text"><input type="text"><input type="text"><input type="text"><input type="text"><div id="div1"><img src="images/1.png"><img src="images/2.png"><img src="images/3.png"><img src="images/4.png"><img src="images/5.png"></div></body></html>
找最小值和位置
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>找最小值和位置</title><script>var arr = [34, 71, 8, 934, 10];var value = 9999;var index = -1;for(var i=0; i<arr.length; i++){if(arr[i]< value){value = arr[i];index = i;}}alert('最小值:' + value + ',位置:' + index);</script></head><body></body></html>
照片墙的实现
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>妙味照片墙效果</title><style>html, body {margin: 0; padding: 0;}#ul1 {width: 660px; position: relative; margin: 10px auto;}li {width: 200px; height: 150px; margin: 10px; float: left; list-style: none;}</style><script>window.onload = function(){//布局转换,将浮动布局转成定位布局var aLi = document.getElementsByTagName('li');var izIndex = 2;var arr = [];var oInput = document.getElementById('input1');for(var i=0; i<aLi.length; i++){arr.push([aLi[i].offsetLeft, aLi[i].offsetTop]);}for(var i=0; i<aLi.length; i++){aLi[i].style.position = 'absolute';aLi[i].style.left = arr[i][0] + 'px';aLi[i].style.top = arr[i][1] + 'px';aLi[i].style.margin = 0; //去掉影响定位的值。例如margin、padding都已经算到left和top里面了,所以不需要再算进去}for(var i=0; i<aLi.length; i++){aLi[i].index = i;drag(aLi[i]);}oInput.onclick = function(){var randomArr = [0, 1, 2, 3, 4, 5, 6, 7, 8];randomArr.sort(function(n1, n2){return Math.random() - 0.5;})for(var i=0; i<aLi.length; i++){startMove(aLi[i], {left: arr[randomArr[i]][0], top: arr[randomArr[i]][1]});aLi[i].index = randomArr[i];}}function drag(obj){var disX = 0;var disY = 0;obj.onmousedown = function(ev){var ev = ev || window.event;obj.style.zIndex = izIndex ++;disX = ev.clientX - obj.offsetLeft;disY = ev.clientY - obj.offsetTop;document.onmousemove = function(ev){var ev = ev || window.event;obj.style.left = ev.clientX - disX + 'px';obj.style.top = ev.clientY - disY + 'px';// for(var i=0; i<aLi.length; i++){// if(pz(obj, aLi[i]) && obj != aLi[i]){// aLi[i].style.border = '2px solid red';// } else {// aLi[i].style.border = '';// }// }var nL = nearLi(obj);for(var i=0; i<aLi.length; i++){aLi[i].style.border = '';}if(nL){nL.style.border = '2px solid red';}}document.onmouseup = function(){document.onmousemove = null;document.onmouseup = null;var nL = nearLi(obj);var tmp = 0;if(nL){startMove(nL, {left: arr[obj.index][0], top: arr[obj.index][1]});startMove(obj, {left: arr[nL.index][0], top: arr[nL.index][1]});nL.style.border = '';tmp = obj.index;obj.index = nL.index;nL.index = tmp;} else {startMove(obj, {left: arr[obj.index][0], top: arr[obj.index][1]});}}return false;}}function nearLi(obj){var value = 9999;var index = -1;for(var i=0; i<aLi.length; i++){if(pz(obj, aLi[i]) && obj != aLi[i]){var c = jl(obj, aLi[i]);if(c<value){value = c;index = i;}}}if(index != -1){return aLi[index];} else {return false;}}function jl(obj1, obj2){var a = obj1.offsetLeft - obj2.offsetLeft;var b = obj1.offsetTop - obj2.offsetTop;return Math.sqrt(a*a + b*b);}function pz(obj1, obj2){var L1 = obj1.offsetLeft;var R1 = obj1.offsetLeft + obj1.offsetWidth;var T1 = obj1.offsetTop;var B1 = obj1.offsetTop + obj1.offsetHeight;var L2 = obj2.offsetLeft;var R2 = obj2.offsetLeft + obj2.offsetWidth;var T2 = obj2.offsetTop;var B2 = obj2.offsetTop + obj2.offsetHeight;if(R1 < L2 || L1 > R2 || B1 < T2 || T1 > B2){ //碰不到的情况return false;} else { //其余都是碰到的情况return true;}}//以下是运动框架move.js的代码function css(obj, attr){if(obj.currentStyle){return obj.currentStyle[attr];} else {return getComputedStyle(obj, false)[attr];}}function startMove(obj, json, fn){clearInterval(obj.iTimer);var iCur = 0;var iSpeed = 0; //速度初始化obj.iTimer = setInterval(function(){var iBtn = true;for(var attr in json){var iTarget = json[attr];if(attr == 'opacity'){iCur = Math.round(css(obj, 'opacity') * 100);} else {iCur = parseInt(css(obj, attr));}iSpeed = (iTarget - iCur) / 8;iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);if(iCur != iTarget){iBtn = false;if(attr == 'opacity'){obj.style.opacity = (iCur + iSpeed) / 100;obj.style.filter = 'alpha(opacity=' + (iCur + iSpeed) + ')';} else {obj.style[attr] = iCur + iSpeed + 'px';}}}if(iBtn){clearInterval(obj.iTimer);fn && fn.call(obj);}}, 30);}}</script></head><body><input type="button" value="随机" id="input1"><ul id="ul1"><li><img src="photo/1.jpg"></li><li><img src="photo/2.jpg"></li><li><img src="photo/3.jpg"></li><li><img src="photo/4.jpg"></li><li><img src="photo/5.jpg"></li><li><img src="photo/1.jpg"></li><li><img src="photo/2.jpg"></li><li><img src="photo/3.jpg"></li><li><img src="photo/4.jpg"></li></ul></body></html>