JS面向對象1

什麼是面向對象編程

  • 用對象的思想去寫代碼,就是面向對象編程css

    • 過程式寫法html

    • 面向對象寫法node

  • 咱們一直都在使用對象jquery

    • 數組Array 時間Date面試

面向對象編程(OOP)的特色

  • 抽象:抓住核心問題編程

  • 封裝:只能經過對象來訪問方法json

  • 繼承:從已有對象上繼承出新的對象數組

  • 多態:多對象的不一樣形態app

對象的組成

  • 方法(行爲、操做) —— 對象下面的函數:過程、動態的ide

  • 屬性 —— 對象下面的變量:狀態、靜態的

建立第一個面向對象程序

//var obj = {};
var obj = new Object(); //建立了一個空的對象
obj.name = '小明'; //屬性
obj.showName = function(){ //方法
    alert(this.name);
}
obj.showName();
  • 爲對象添加屬性和方法

    • Object對象

    • this指向

    • 建立兩個對象:重複代碼過多

//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指向爲新建立的對象

/* 當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();

構造函數
用來建立對象的函數,叫作構造函數
存在的問題
一、對象的引用
2.浪費內存

/* 當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); //8
    alert(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
*/

原型 —— prototype

概念
去改寫對象下面公用的方法或者屬性,讓公用的方法或者屬性在內存中僅存在一份(好處:提升性能)

學習原型

  1. 類比:原型就是CSS中的class(普通方法就是CSS中的style)

  2. 普通方法的優先級比原型要高

  3. 原型能夠複用,普通方法不能夠複用

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());

經過原型改寫工廠方式原則:

  1. 相同的屬性和方法能夠加在原型上

  2. 混合的編程模式

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.方法();

總結面向對象寫法:構造函數加屬性,原型加方法

面向對象的選項卡

原則
先寫出普通的寫法,而後改爲面向對象寫法

  • 普通方法變型

    • 儘可能不要出現函數嵌套函數

    • 能夠有全局變量

    • 把onload中不是賦值的語句放到單獨的函數中

  • 改爲面向對象

    • 全局變量就是屬性

    • 函數就是方法

    • onload中建立對象

    • 改this指向問題,要儘可能讓面向對象中的this指向對象

一、先寫出普通方法

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

面向對象的拖拽

注意

  1. Event對象(event對象必定要寫到事件函數裏面)

  2. 事件函數中用來阻止默認行爲的return false也要寫到事件函數裏面

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

本課練習

  1. 爲數組對象添加求和,最大值

  2. 爲字符串對象添加判斷是否是最後一個字母

  3. 面向對象的選項卡

  4. 給選項卡添加一個自動播放的方法

  5. 任意學過的效果改寫成面向對象

  6. 面向對象的面試題

高級面向對象

包裝對象

JS基於原型的程序
String Number Boolean

<!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方法,那麼後面那一句中的四、五、6就添加不進去了
    Array.prototype.push = function(){ //本身寫一個數組的push方法
        //this : 1, 2, 3
        //arguments: 4, 5, 6

        for(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); //string
        str.charAt(0); //字符串爲何下面會有方法呢?
        str.indexOf('e');
    */

    //包裝對象:基本類型都有本身對應的包裝對象(String, Number, Boolean)(null和undefined沒有包裝對象)

    /*
    var str = new String('hello');
    alert(typeof str); //object
    alert(str.charAt(1)); //彈出e

    String.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()); //o
    
    var str1 = 'hello';
    str1.number = 10; //在str1的包裝對象上建立了一個number,而後包裝對象就消失了
    alert(str1.number); //undefined 再去調用這句話的時候,此時又從新建立了一個對象,這個對象與剛纔那個對象不是同一個    

    </script>
</head>
<body>
</body>
</html>

原型鏈

  • 實例對象與原型之間的鏈接,叫作原型鏈

  • proto (隱式鏈接)

  • Object對象類型是原型鏈的最外層

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>面向對象中的原型鏈</title>
    <style></style>
    <script>
    
        //原型鏈:實例對象與原型之間的鏈接叫做原型鏈
        //_proto_ (隱式鏈接)
        //原型鏈的最外層是Object.prototype

        function Aaa(){
            
        }

        Aaa.prototype.num = 10;

        var a1 = new Aaa();
        alert(a1.num); //10 a1如今它本身下面找,找不到這個num,而後又經過原型鏈到了Aaa.prototype,到它下面去找,最終找到了num

        function 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,找到了num
        alert(c1.num);
    </script>
</head>
<body>
</body>
</html>

面向對象的一些屬性和方法

hasOwnProperty()看是否是對象自身下面的屬性

<!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')); //true
        alert(arr.hasOwnProperty('num2')); //false
        alert(arr.hasOwnProperty == Object.prototype.hasOwnProperty); //true hasOwnProperty實際上是Object.prototype下面的方法
    </script>
</head>
<body>
</body>
</html>

constructor查看對象的構造函數

  • 每一個原型都會自動添加constructor屬性

  • for in 的時候,有些屬性是找不到的

  • 避免修改constructor屬性

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

        var arr = [];
        alert(arr.constructor == Array); //true

        /*
        在寫完一個構造函數以後
        function Aaa(){}
        程序會自動添加一句話:
        Aaa.prototype.constructor = Aaa; //每個函數都會有的,都是自動生成的
        這時候new一個Aaa
        var 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>

instanceof運算符

對象與構造函數在原型鏈上是否有關係
能夠用來做類型判斷

<!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); //false
        alert(a1 instanceof Object); //true
    </script>
</head>
<body>
</body>
</html>

toString()

object上的方法

<!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()); //string

        alert(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>

對象的繼承

什麼是繼承

  • 在原有對象的基礎上,略做修改,獲得一個新的對象

  • 不影響原有對象的功能

如何添加繼承

  • 屬性:call

  • 方法:for in

  • 例子:繼承的拖拽

!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也是採用拷貝繼承extend

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

原型繼承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>原型繼承</title>
    <style>
    </style>
    <script>
        var a = {
            name: '小明'
        }

        var b = cloneObj(a); //讓b繼承a
        b.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>
  • 拷貝繼承:通用型的 有new或無new的時候均可以

  • 類式繼承:適合經過new構造函數形式

  • 原型繼承:比較適合無new的對象

組件開發

一、對象的多種表現形式

  • 提升對象的複用性

  • 如何配置參數和默認參數

  • 例子:拖拽

  • 例子:彈窗

二、什麼是組件?

  • 對面向對象的深刻應用(UI組件、功能組件)

  • 將配置參數、方法、事件、三者進行分離

三、建立自定義事件

  • 有利於多人協做開發代碼

  • 如何去掛載自定義事件與事件函數

四、例子:基於JQ的選項卡的組件開發模式
trigger() extend()等方法的使用
五、本課練習
組件開發的練習
http://tangram.baidu.com/magic/

如何配置參數和默認參數

<!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, 4
            fireEvent(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>

配置、方法、自定義事件分離

——正規組件的寫法——基於拖拽的組件進行的修改

<!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 &amp;&amp; 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 
            - delay
        Methods: 
            - 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' &amp;&amp; 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>
相關文章
相關標籤/搜索