JS面向对象及组件开发课件

什么是面向对象

 /*
    * 什么是面向对象编程?
    *  - 用对象的思想去写代码,就是面向对象编程
    *   - 过程式写法
    *   - 面向对象写法
    * */

面向对象编程的特点

    /*
    * OP编程的特点
    *  - 抽象:抓住核心问题
    *  - 封装:只能通过对象来访问方法
    *  - 继承:从已有对象上继承出新的对象
    *  - 多态:多对象的不同形态
    * */

面向对象的基本写法和组成

    /*
    * 有两部分组成
    *   - 方法[可以去做某件事]
    *   - 属性[对象下面的方法]   //不加括号是是属性,加括号是方法
    *
    * */
    //var obj = {};//创建了一个json
    var obj = new Object();//和上面的一样。创建了一个空的对象


    obj.name = '小明';//属性
    obj.showName = function(){//方法

        alert(obj.name);
//        alert(this.name);
    }
    /*
    * this 谁调用的this就会指向谁
    * */

    obj.showName();

工厂方式和构造函数

/*
* 工厂方式就相当于封装函数
*
* 创建的对象new在里面,系统对象直接new
* 系统对象第一个是大写
* */
    function  createPerson(name){
        var obj = new Object();
        obj.name = name;
        obj.showName = function(){
            alert(this.name);
        };
        return obj;
    }

createPerson('小明').showName();
createPerson('小强').showName();
/*
* 工厂方式就相当于封装函数
*
* 创建的对象new在里面,系统对象直接new
* 系统对象第一个是大写
*
* 当new去调用一个函数:这个时候函数中的this就是创建出来的对象,而且函数的返回值直接就是this[隐式返回],不用谢return

new后面的函数叫做构造函数
* */

    function  CreatePerson(name){
        this.name = name;
        this.showName = function(){
            alert(this.name);
        };
    }

var p1 = new CreatePerson('小明');
p1.showName();
var p2 = new CreatePerson('小强');
p2.showName();

对象引用是什么和它的问题

alert(p1.showName == p2.showName);//false
基本类型和对象类型的复制区别:复制和引用
对象的值和引用都相同才行

如何让同样的方法只存在一份?
使用原型:去改写对象下面公用的方法或属性,让公用的东西在内存中只存在一份[好处就是提高性能]

面向对象之原型学习

   /*原型:去改写对象下面公用的方法或者属性,让公用的方法火属性在内存中存在一份[提高性能]*/
    /*
    * 
    * 
    * 概念:重写对象方法,让相同的方法在内存中存在一份[提高性能]
    * 类比:CSS中的class
    * 通过原型改写工厂方法
    *   > 相同的属性和方法可以加载在原型上
    *   > 混合的编程模式
    *   
    *  总结面向对象方法
    *   - 构造函数加属性,原型和方法
    * */
    /*
    * 原型:prototype 要写在构造函数下面
    * */


/*    var arr = [1,2,3,4,5];
    var arr2 = [1,2,3,4,5];

    arr.sum = function(){
        var result = 0;
        for(var i=0;i<this.length;i++){
            result+=this[i];
        }
        return result;
    }
    console.log(arr.sum());
    //console.log(arr2.sum());//这样是会报错的*/

    var arr = [1,2,3,4,5];
    var arr2 = [1,2,43,4,5];

    Array.prototype.sum = function(){
        var result = 0;
        for(var i=0;i<this.length;i++){
            result+=this[i];
        }
        return result;
    }

    alert(arr.sum());
    alert(arr2.sum());
//类比:style的优先级要比class的优先级要高.[遵从就近属性]
    var arr = [];
    arr.number = 10;
    Array.prototype.number = 20;
    alert(arr.number);
//显示的就是true
// 原型上面的东西是公用的
    function createPerson(name){

        this.name = name;
    }
    createPerson.prototype.showName = function(){
        alert(this.name);
    }
    var p1 = new createPerson('小强');
    p1.showName();
    var p2 = new createPerson('小红');
    p2.showName();

    alert(p1.showName  == p2.showName);//false

传统的过程式编写选项卡

 /*
     * 先变型,变型的原则:
     *   尽量不要出现函数嵌套函数
     *   可以有全局变量
     *   把onload中不是赋值的语句放到单独函数中
     *
     * */

init();//初始化方法

用面向对象封装通用选项卡

    /*
     * 先变型:
     *   尽量不要出现函数嵌套函数
     *   可以有全局变量
     *   把onload中不是赋值的语句放到单独函数中
     *
     *  改成面向对象:
     *      全局变量其实就是属性,
     *      函数就是方法,
     *     onload中就是创建对象
     *     改this指向问题,尽量让面向对象中的this指向对象
     * */


      window.onload = function(){
        var ti = new Tab();
        ti.init();
    }

    function Tab(){
        this.getDiv = document.getElementById('div1');
        this.getSonDiv= this.getDiv.getElementsByTagName('div');
        this.getSonInput= this.getDiv.getElementsByTagName('input');
    }

    Tab.prototype.init = function(){

        This = this;
        for(var i=0;i<this.getSonInput.length;i++){

            this.getSonInput[i].index = i;

            this.getSonInput[i].onclick = function(){

                This.change(this);
            };

        }
    }

    Tab.prototype.change = function(obj){

        for(var i =0;i<this.getSonInput.length;i++){
            this.getSonInput[i].className = '';
            this.getSonDiv[i].style.display = 'none';
        }

        this.getSonDiv[obj.index].style.display = 'block';
        obj.className = 'active';
    }

控制多个选项卡自动播放

<script>
    window.onload = function(){

        var t1 = new Tab('div1');
        t1.init();

        var t2 = new Tab('div2');
        t2.init();
        t2.autoPlay();
    }

    function Tab(id){
        this.getDiv = document.getElementById(id);
        console.log(this);
        this.getSonDiv= this.getDiv.getElementsByTagName('div');
        this.getSonInput= this.getDiv.getElementsByTagName('input');
        this.iNow = 0;
    }

    Tab.prototype.init = function(){

        var This = this;
        for(var i=0;i<this.getSonInput.length;i++){

            this.getSonInput[i].index = i;

            this.getSonInput[i].onclick = function(){

                This.change(this);
            };

        }
    }

    Tab.prototype.change = function(obj){

        for(var i =0;i<this.getSonInput.length;i++){
            this.getSonInput[i].className = '';
            this.getSonDiv[i].style.display = 'none';
        }

        this.getSonDiv[obj.index].style.display = 'block';
        obj.className = 'active';
    }

    Tab.prototype.autoPlay = function(){

        var This = this;

        setInterval(function(){

            This.iNow++;
            This.iNow%=This.getSonInput.length;

            for(var i =0;i<This.getSonInput.length;i++){
                This.getSonInput[i].className = '';
                This.getSonDiv[i].style.display = 'none';
            }

            This.getSonInput[This.iNow].className = 'active';
            This.getSonDiv[This.iNow].style.display = 'block';
        },1000);
    }
</script>

在定时器中,this会指向window

用面向对象编写拖拽

    /*
    * 原则是使得this指向此对象
    * */
    window.onload = function(){

        var t1 = new Tab('div1');
        t1.init();
        var t2 = new Tab('div2');
        t2.init();


    }


    function Tab(id){
         this.getDiv = document.getElementById(id);
         this.disX = 0;
         this.disY = 0;
    }

    Tab.prototype.init = function(){
        /*
        * 在监听器与定时器上面容易出现问题。现在this指向的是div
        * */
        var This = this;
        this.getDiv.onmousedown = function(ev){
            var ev = ev||event;
            This.fnDown(ev);
            return false;
        };
    }

    Tab.prototype.fnDown=function(ev){

        var This = this;
         this.disX = ev.clientX - this.getDiv.offsetLeft;
         this.disY = ev.clientY - this.getDiv.offsetTop;

        document.onmousemove = function(){
            var ev = ev||event;
            This.fnMove(ev);
        };

        document.onmouseup = this.fnUp;
    }

    Tab.prototype.fnMove=function(ev){

        this.getDiv.style.left = ev.clientX - this.disX +'px';
        this.getDiv.style.top = ev.clientY - this.disY +'px';
    }

    Tab.prototype.fnUp = function(){

        document.onmouseup = document.onmousemove = null;
    }
    /*
    * 尽量不要出现嵌套函数
    * 可以有全局变量
    * 把onload中不是赋值的语句放到淡出的函数中去
    * */

JS是基于原型的程序

var num = [1,2,3];


Array.prototype.push = function(){

    for(var i=0;i<arguments.length;i++){
        this[this.length]= arguments[i];
    }
    return this.length;
}

console.log(num.push(4,5,6));
console.log(num);

    /*
    *
    * 系统对象也是基于原型的程序
    *
    * 千万不要修改系统方法
    * */

什么是包装对象

    /*
    *
    *
    *
    * 包装对象:基本类型都有自己对应的包装对象
    * 除了null,undefined。
    * */

    var str = 'hello';
    alert(typeof str);
    str.charAt();//基本类型会找到对应的包装对象类型,然后包装对象把所有的属性和方法给了基本类型,然后包装对象消失。
    //特别像送快递

    /*
    * 通过new创建的都是基本对象
    * */

    //String.prototype.charAt = function(){}

    String.prototype.lastValue = function(){
        return this.charAt(this.length-1);
    }

    alert(str.lastValue());//自己创建的方法
    var str = 'hello';
    str.num =10;

    alert(str.num);
    /*
    * 基本类型想要添加一个属性,就会在基本而类型的包装对象上去创建一个对象,然后包装对象消失。
    * 
    * 而原型下面的方法是共享的
    * */

面向对象中的原型链

aaa.prototype.num = 10; //这个时候num是挂在在aaa的原型下面

为什么对象可以找到原型下面的东西?
是通过原型链_proto_找到的

    /*
    *    实例对象与原型之间的连接,叫做原型链
    *
    *    原型链的最外层是 Object.prototype
    * */

    function aaa(){
//        this.num = 'missXiao';
    }
//    aaa.prototype.num = 10;
    Object.prototype.num = '666';
    var a1 = new aaa();
    console.log(a1.num);

hasOwnProperty和constructor的使用

    /*
    *
    * 面向对象的一些属性和方法
    *   - hasOwnProperty():看是不是对象自身下面的属性
    *   - constructor:查看对象的构造函数
    *       - 每个原型都会自动添加constructor属性
    *       - 避免修改construtor属性
    *
    *   - instanceof 运算符
    *       - 对象与构造函数在原型链上是否有关系
    *
    *   - toString();object上的方法
    * */

    var arr = [];
//    arr.num = 10;
    arr.num=10;
    Array.prototype.num2 = function(){
        alert(66);
    };

    //看看是不是对象自身下面的属性
    console.log(arr.hasOwnProperty('num'));//true
    console.log(arr.hasOwnProperty('num2'));//false

    //constructor查看对象的构造函数。[和原型没有关系]
    console.log(arr.constructor);


    function newFn(){
        this.color = 'color';
        this.red = 'red';
    }

    var fn = new newFn();
    console.log(fn.constructor);
//创建完函数之后,程序会自动的添加这句话

function newFn(){
        this.color = 'color';
        this.red = 'red';
    }

    newFn.prototype.constructor = Array;//如果修改的话就会改回Array[每一个函数都会有的,都是自动生成的]
    newFn.prototype.constructor = newFn;

hasOwnProperty是调用最外层Object上面。
console.log(fn.hasOwnProperty == Object.prototype.hasOwnProperty);//返回的是true

    function aaa(){

    }
//    aaa.prototype.name = '小明';
//    aaa.prototype.age = 18;

    aaa.prototype = {
        constructor:aaa,//一定要把原型给修正过来
        'name':'小明',
        'age':18
    }//这样写不会覆盖constructor,因为是往原型上添加的
    var t1 = new aaa();

    console.log(t1.name);

使用for-in,系统自带的属性有些是找不到的。

    //这样做只能够弹出一个name[即使修改constructor,也是找不到的]
    bbb.prototype.name =66;
    for(var attr in bbb.prototype){

        console.log(attr);
    }

instanceof运算符的使用

    //instanceof其实是一个运算符。对象与构造函数在原型链上是否有关系
    function Aa(){

    }

    var a1 = new Aa();

    console.log(a1 instanceof Aa);
    console.log(a1 instanceof Object);

constructor和instanceof也能查看类型,但是最好的查看方法是tostring

利用toString做类型判断

    var arr = [];
    console.log(arr.toString);

    function Aaa(){

    }
    var a1 = new Aaa();

    /*
    * 系统下面的toString是自带的,自己写的对象都是通过原型链进行查找的
    *
    * */
    console.log(arr.toString == Object.prototype.toString);//结果是false。
    console.log(a1.toString == Object.prototype.toString);//结果是true
    //toString()把对象转成字符串

    var arr =[1,2,3];

    console.log(arr.toString());//转换成字符串

    Array.prototype.toString = function(){//自定义转换成字符串
        return this.join('+');
    }
    console.log( arr.toString());

    /*
    * 进行进制转换
    * */
    var num =255;
    console.log(num.toString(16));


    /*
    * 做类型判断
    * */
    var arr = [];

    /*建议使用这一个来判断*/
    /*
    * 跨域情况下,进行判断会错误
    * */
    console.log(Object.prototype.toString.call(arr)=='[object Array]');

什么是面向对象的继承

这里方法的继承有问题

    /*
    * 什么是继承[复用代码的一种形式]
    *   在原有对象的基础上,略作修改,得到一个新的对象
    *   不影响原有对象的功能
    *
    * 如何添加继承
    *   属性 call
    *   方法 for in
    *
    * */


    /*
    * 属性的继承:调用父类的构造函数 call
    *
    *  方法的继承:父类的原型赋给子类的原型
    * */
    function CreatePerson(name,sex){
        this.name = name;
        this.sex = sex;
    }
    CreatePerson.prototype.showName = function(){
        console.log(this.name);
    }

    function CreateStar(name,sex,job){
        CreatePerson.call(this,name,sex);
        this.job = job;
    }

    CreateStar.prototype = CreatePerson.prototype;
    var p1 = new CreatePerson('小明','男');
    p1.showName();

    var p2 = new CreatePerson('黄晓明','男','演员');
    p2.showName();

面向对象之拷贝继承

    /*
    * 什么是继承[复用代码的一种形式]
    *   在原有对象的基础上,略作修改,得到一个新的对象
    *   不影响原有对象的功能
    *
    * 如何添加继承
    *   属性 call
    *   方法 for in[拷贝继承]
    *
    * */


    /*
    * 属性的继承:调用父类的构造函数 call
    *
    *  方法的继承:父类的原型赋给子类的原型
    * */
    function CreatePerson(name,sex){
        this.name = name;
        this.sex = sex;
    }
    CreatePerson.prototype.showName = function(){
        console.log(this.name);
    }

    function CreateStar(name,sex,job){
        CreatePerson.call(this,name,sex);
        this.job = job;
    }

    extend(CreateStar.prototype,CreatePerson.prototype);
//    CreateStar.prototype = CreatePerson.prototype;
    var p1 = new CreatePerson('小明','男');
    p1.showName();

    var p2 = new CreateStar('黄晓明','男','演员');
    p2.showName();


    function extend(obj1,obj2){
        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }

    console.log(p1)
    console.log(p2)

函数不能被修改,如果一赋值就会被改变链条

    var a = [1,2,3];
    var b =a;
    b = [1,2,3,4];

编写继承的拖拽

    window.onload = function(){

        var t1 = new Tab('div1');
        t1.init();
        var t2 = new TabSon('div2');
        t2.init();
    }

    function Tab(id){

        this.div = document.getElementById(id);
        this.disX = 0;
        this.disY = 0;
    }

    Tab.prototype.init = function(){

        var This = this;

        this.div.onmousedown = function(ev){

            var ev = ev||event;
            This.disX = ev.clientX - this.offsetLeft;
            This.disY = ev.clientY - this.offsetTop;

            console.log(This.disX);

            document.onmousemove = function(ev){

                var ev = ev||event;
                This.fnMove(ev);
            }
            document.onmouseup = This.fnUp;
        }
    }


    Tab.prototype.fnMove = function(ev){

        this.div.style.left = ev.clientX - this.disX +'px';
        this.div.style.top = ev.clientY - this.disY +'px';
    }

    Tab.prototype.fnUp = function(){

        document.onmouseup = document.onmousemove = null;
    }


    
    /*
    *
    * 继承
    * */
    function TabSon(id){
        Tab.call(this,id);
    }


    extend(TabSon.prototype,Tab.prototype);


    TabSon.prototype.fnMove = function(ev){

        var L = ev.clientX - this.disX;
        var T = ev.clientY - this.disY;


        console.log(document.documentElement.clientHeight);
        if(L<0){
            L=0;
        }else if(L>document.documentElement.clientWidth - this.div.offsetWidth){
            L = document.documentElement.offsetWidth - this.div.offsetWidth;
        }
        if(T<0){
            T=0;
        }else if(T>document.documentElement.clientHeight - this.div.offsetHeight){
            T = document.documentElement.clientHeight - this.div.offsetHeight;
        }
        this.div.style.left = L +'px';
        this.div.style.top = T +'px';
    }



    /*
    * 继承函数
    * */
    function extend(obj1,obj2){

        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }

继承的其他形式之类式继承

    /*
    *
    * 继承的其他形式
    *   - 类式继承
    *       - 利用构造函数[类]继承的方法
    *   - 原型继承
    *       - 借助原型来实现对象继承对象
    *
    *
    *在JS里是没有类的概念的,可以把构造函数想象成类
    * */

    function Aaa(){
        this.name = [1,2,3];
    }
    Aaa.prototype.showName = function(){
        console.log(this.name);
    }

    function Bbb(){
        Aaa.call(this);
    }
    
    
    /*至少需要四句话。
    * 目的是只继承方法,而不继承属性
    * */
    var F = function(){};
    F.prototype = Aaa.prototype;
    Bbb.prototype = new F();
    Bbb.prototype.constructor = Bbb;

    var b1 = new Bbb();
    b1.showName();
    b1.name.push(1);
    console.log(b1);

    var b2 = new Bbb();
    console.log(b2);

继承的其他形式之原型继承

借助原型来实现对象继承对象


继承
      //原型继承
    var a = {
        name:'小明'
    }

      var b= cloneObj(a);

      alert(b.name);//小明

      b.name = '666';

      alert(b.name);//666

      alert(a.name);//小明

      



    function cloneObj(obj){

        /*三句话组合到一起就是原型继承*/
        var F = function(){};
        F.prototype = obj;
        return new F();
    }

原型也是对象

/*
* 拷贝继承:通用型的 [有new或者无new都适用]
*
* 类式继承:适用于new构造函数形式
*
* 原型继承:适用于无new的对象
* */

组件开发是什么

<script>

    /*
    *
    * 需求:黄的按下的时候title是有变化的,而红的是没有变化的
    *
    * */
    
    /*
    * 
    * 参数报错和参数顺序问题
    * 
    * */
    window.onload = function () {

        var t1 = new Tab();
        t1.init('div1');
        var t2 = new Tab();
        t2.init('div2',function (){
            document.title = 'hello';
        });
    };

    /*传参可以写到构造函数当中,也可以写到初始化当中*/

    function Tab(){
        this.div = null;
        this.disX = 0;
        this.disY = 0;
    }

    Tab.prototype.init = function(id,todown){
        this.div = document.getElementById(id);
        var This = this;

        this.div.onmousedown = function(ev){

            var ev = ev||event;
            This.disX = ev.clientX - this.offsetLeft;
            This.disY = ev.clientY - this.offsetTop;

            todown&&todown();

            document.onmousemove = function(ev){

                var ev = ev||event;
                This.fnMove(ev);
            }
            document.onmouseup = This.fnUp;
        }
    }


    Tab.prototype.fnMove = function(ev){

        this.div.style.left = ev.clientX - this.disX +'px';
        this.div.style.top = ev.clientY - this.disY +'px';
    }

    Tab.prototype.fnUp = function(){

        document.onmouseup = document.onmousemove = null;
    }



    /*
     * 组件开发更像是一种兄弟的关系
     *   用同一套代码满足不同的产品需要求
     *
     *   好处:
     *       - 提高产品的复用性
     *       - 如何配置参数和默认参数
     *
     * */

    // 组件开发:多组对象,像兄弟之间的关系[代码复用的一种形式]



    /*
     * 继承函数
     * */
    function extend(obj1,obj2){

        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }
</script>

给拖拽组件配置不同参数

<script>
    /*
    * 可以利用json的特性,使得一个参数代表多个值。json整体是一个参数
    *
    * */

    var a = {//a在程序中叫做配置参数
//        name:'小明'
    }

    var b = {//默认参数
        name:'小强'
    }


    extend(b,a);
    console.log(b.name);//现在b的name等于小明,说明被覆盖掉

    function extend(obj1,obj2){

        for(var attr in obj2){
            obj1[attr] =obj2[attr];
        }
    }
</script>
<script>
    /*
    * 解决的是两个问题:
    *   - 参数顺序问题?
    *       - 使用json
    *   - 如果为空怎么办?
    *       - 配置参数
    * */

    window.onload = function () {

        var t1 = new Tab();
        t1.init({//配置参数
            id:'div1'
        });

        var t2 = new Tab();
        t2.init({//配置参数
            id:'div2',
            toDown:function(){
                document.title = 'hello'
            }
        });

        var t3 = new Tab();
        t3.init({//配置参数
            id:'div3',
            toDown:function(){
                document.title = 'miaov'
            },
            toUp:function(){
                document.title = '课堂'
            }
        });


        var t4 = new Tab();
        t4.init({//配置参数
            id:'div4',
            toUp:function(){
                document.title = '拜拜'
            }
        });
    };


    function Tab(){
        this.div = null;
        this.disX = 0;
        this.disY = 0;

        this.settingss = {//默认参数.[id是没有默认参数的,是必选项]
            toDown:function(){},
            toUp:function(){}
        }
    }

    Tab.prototype.init = function(opt){
        this.div = document.getElementById(opt.id);
        var This = this;

        extend(this.settingss,opt);//配置赋给默认

        this.div.onmousedown = function(ev){

            var ev = ev||event;
            This.disX = ev.clientX - this.offsetLeft;
            This.disY = ev.clientY - this.offsetTop;

            This.settingss.toDown();

            document.onmousemove = function(ev){

                var ev = ev||event;
                This.fnMove(ev);

            }
            document.onmouseup = function() {
                This.settingss.toUp();
                This.fnUp();
            }
        }
    }


    Tab.prototype.fnMove = function(ev){

        this.div.style.left = ev.clientX - this.disX +'px';
        this.div.style.top = ev.clientY - this.disY +'px';
    }

    Tab.prototype.fnUp = function(){

        document.onmouseup = document.onmousemove = null;
    }



    /*
     * 组件开发更像是一种兄弟的关系
     *   用同一套代码满足不同的产品需要求
     *
     *   好处:
     *       - 提高产品的复用性
     *       - 如何配置参数和默认参数
     *
     * */

    // 组件开发:多组对象,像兄弟之间的关系[代码复用的一种形式]



    /*
     * 继承函数
     * */
    function extend(obj1,obj2){

        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }
</script>

封装弹框组件

<script>

    //采用的是动态创建的形式

    window.onload = function(){

        var aInput = document.getElementsByTagName('input');

        aInput[0].onclick = function(){

            var d1 = new Dialog();
            d1.init({//传入配置参数
                title:'登陆'
            });
        }

        aInput[1].onclick = function(){

            var d1 = new Dialog();
            d1.init({//传入配置参数
                w:100,
                h:400,
                dir:'right',
                title:'公告'
            });
        }
    }

    function Dialog(){

        this.settings = {//所有参数都走默认
            w:300,
            h:300,
            dir:'center',
            title:'标题'
        }
    }

    Dialog.prototype.init = function(opt){

        this.oLogin = null;
        extend(this.settings,opt);
        this.create();
    }

    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';
        }
    }



    function extend(obj1,obj2){//obj1是空,obj2是被

        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }

    function viewWidth(){
        return document.documentElement.clientWidth;
    }

    function viewHeight(){
        return document.documentElement.clientHeight;
    }
</script>

使用对象标记已弹出弹框

只让执行一次的过程是单体模式

<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 d1 = new Dialog();
            d1.init({//传入配置参数
                iNow:1,
                w:100,
                h:400,
                dir:'right',
                title:'公告'
            });
        }

        aInput[2].onclick = function(){

            var d1 = new Dialog();
            d1.init({//传入配置参数
                iNow:2,
                mark:true
            });
        }
    }


    function Dialog(){

        this.settings = {//所有参数都走默认
            w:300,
            h:300,
            dir:'center',
            title:'默认',
            mark:false//默认遮罩是没有的
        }
    }

    Dialog.prototype.json = {//使用json来达到只能够走一次的效果

    };

    Dialog.prototype.init = function(opt){

        this.oLogin = null;
        extend(this.settings,opt);
        //console.log(this.json[opt.iNow] == undefined);//这里有一个重要区别,一定要注意

        /*
        * 把opt换成this.settings?
        * */
        if(this.json[opt.iNow]==undefined) {

            this.json[opt.iNow] = true;
        }

        if(this.json[opt.iNow]){

            this.create();
            this.fnClose();
//        console.log(this.settings.mark);
            this.settings.mark && this.createMark();

            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(){
            this.parentNode.parentNode.remove();

            if(This.settings.mark){

                document.body.removeChild(This.oMark);
            }
            console.log(This.json[This.settings.iNow]);
            This.json[This.settings.iNow] = true;
        }
    }

    Dialog.prototype.createMark =  function(){

        var oMark = document.createElement('div');
        oMark.id = 'mark';

        this.oMark = oMark;//通过动作可以生成属性
        oMark.style.width = viewWidth()+'px';
        oMark.style.height = viewHeight()+'px';
        document.body.appendChild(oMark);
    }

    function extend(obj1,obj2){//obj1是空,obj2是被

        for(var attr in obj2){
            obj1[attr] = obj2[attr];
        }
    }

    function viewWidth(){
        return document.documentElement.clientWidth;
    }

    function viewHeight(){
        return document.documentElement.clientHeight;
    }
</script>

复杂组件开发之自定义事件

<script>
    /*
    * 什么是组件?
    *   - 对面向对象的深入应用(UI组件 功能组件)
    *   - 将配置参数,方法,事件,三者进行分离
    *
    * 创建自定义事件:[主要是和函数有关系,就是让函数能够具备事件的某些特性]
    *
    *   - 有利于多人协作开发代码
    *   - 如何去挂载自定义事件与事件函数
    * */

    var btn1 = document.getElementById('btn1');


    btn1.addEventListener('show',function(){
        alert(1);
    },false);
    btn1.addEventListener('show',function(){
        alert(2);
    },false);
    btn1.addEventListener('show',function(){
        alert(3);
    },false);
    btn1.addEventListener('show',function(){
        alert(4);
    },false);

    show();//主动触发自定义事件
</script>

原生JS实现自定义事件

简述一下,这里的自定义事件就相当于楼层->书架->书的关系。json就是一个楼层,他通过元素的自定义属性挂载在元素身上,数组就相当于书架,存在与json之中。而书就是一个个函数啦

<script>
    /*
    * 绑定事件的特点就是互相不会覆盖
    * */

    /*
    *
    * 自定义事件是函数,一个是函数名,一个是函数内容
    * */


    window.onload = function(){

        var oDiv = document.getElementsByTagName('div')[0];
        var oSpan = document.getElementsByTagName('span')[0];

        bindEvent(oDiv,'click',function(){
            alert(1);
        })
        bindEvent(oSpan,'show',function(){
            alert(4);
        });

        bindEvent(oSpan,'hide',function(){
            alert(5);
        });

        fireEvent(oDiv,'click');//希望弹出的结果是3,4
    }

    /*
    * 封装绑定事件
    * */
    function bindEvent(obj,events,fn){

        /*
        * obj->楼层
        *event->书架
        * fn ->书
        * */
        obj.listeners = obj.listeners||{};//如果没有就会走后面。[相当于楼层]
        obj.listeners[events] = obj.listeners[events]||[];//[相当于书架]
        obj.listeners[events].push(fn);


        if(obj.addEventListener){
            obj.addEventListener(events,fn,false);
        }else{
            obj.attachEvent('on'+events,fn);
        }
    }



    /*
    * 进行主动触发自定义事件,一般主动触发的函数名叫做fireEvent
    *
    * */
    function fireEvent(obj,events){

        for(var i=0;i<obj.listeners[events].length;i++){

            obj.listeners[events][i]();//主动触发
        }
    }
</script>

自定义事件实例

<script>

    /*需求:
    *   - 采用组件开发的模式
    *   - 并且使用自定义事件,方便多人协同开发
    *
    *
    * */

    window.onload = function(){

        var t1 = new Tab();
        t1.init({
            elem:'div1',
        });


        //寒暑假上括号,表示已经执行

        bindEvent(t1,'Mdown',function(){
           document.title = 'This is T1 mouseDown';
        });

        bindEvent(t1,'Mup',function(){
            document.title = 'This is T1 mouseDown';
        });

        //这里是执行的
        console.log(fireEvent(t1,'Mup'));
    }

    //对象
    function Tab(){

        this.obj = null;
        this.disX = 0;
        this.disY = 0;
        this.settings ={
        };
    }

    Tab.prototype.init = function(opt){

        var This = this;
        extend(this.settings,opt);//固定函数替换完毕

        this.obj = document.getElementById(this.settings['elem']);

        console.log(fireEvent(this,'Mup'));

        this.obj.onmousedown = function(ev){

            fireEvent(This,'Mdown');
//            This.settings.elemDown();
            This.disX =  ev.clientX - this.offsetLeft;
            This.disY = ev.clientY - this.offsetTop;

            document.onmousemove = function(){//这里会发生一个指向性错误

                This.FnMove();
            };

            document.onmouseup = function(){
                This.FnUp();
                fireEvent(This,'Mup');
//                This.settings.elemUp();
            };
        }

    }

    /*
    * 对象的移动动作
    * */
    Tab.prototype.FnMove = function(ev){

        var ev = ev||event;

        this.obj.style.left = ev.clientX - this.disX + 'px';
        this.obj.style.top = ev.clientY - this.disY + 'px';
    }

    /*
    * 对象的清空动作
    * */
    Tab.prototype.FnUp = function(){
        document.onmouseup = document.onmousemove = 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){
            if(obj.addEventListener){
                obj.addEventListener(events,fn,false);
            }else{
                obj.attachEvent('on'+events,fn);
            }
        }
    }

    /*处理注册事件函数*/
    function fireEvent(obj,events){

        console.log(obj.listeners);
        if(obj.listeners&&obj.listeners[events]){
        for(var i =0;i<obj.listeners[events].length;i++){

            obj.listeners[events][i]();
            }
        }
    }
</script>

基于JQ的选项卡组件开发

未学习,之后学习。/

图片放大镜效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>30_基于JQ的选项卡组件开发</title>
    <style>
/*        *{
            margin: 0px;
            padding: 0px;
        }*/
        #div1{
            width: 180px;
            height: 180px;
            overflow: hidden;
            position: relative;
        }
        #div1 span{
            width: 100px;
            height: 100px;
            background-color: yellow;
            opacity: 0.5;
            position: absolute;
            left: 0px;
            top: 0px;
            display: none;
        }
    </style>
</head>
<body>

<div id="div1">
    <img src="images/b2.jpg" alt="">
    <span></span><!--表示遮罩-->
</div>

<script>
    window.onload = function(){

        var oDiv = document.getElementById('div1');
        var oSpan =oDiv.getElementsByTagName('span')[0];

        oDiv.onmouseover = function(){
            oSpan.style.display = 'block';
        }

        oDiv.onmouseout = function(){
            oSpan.style.display = 'none';
        }
        oDiv.onmousemove = function(ev){

            var ev = ev||event;
            /*left与top是相对于父级来进行定位的*/
            console.log(oDiv.offsetLeft);//是相当于屏幕左边
            oSpan.style.left = ev.clientX - oDiv.offsetLeft - oSpan.clientWidth/2 +'px';
            oSpan.style.top = ev.clientY - oDiv.offsetTop-oSpan.clientHeight/2+'px';
        }
    }
</script>
</body>
</html>
        /*
        * 移入是1,移出是2
        * */
        //如果移到黄色方块上是 1,2,1.
        // 移入1.移出2.之后是移到黄色方块上,进行冒泡移入显示1
        //与 onmouseout与onmouseover 事件不同,只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。他们俩通常是在一起用
        //子集就相当于空气
  /*
    *
    * 解决方案有两种
    *   - JS:使用onmouseenter与onmouseleave。这两个的特点就是子集不会影响到父级[他俩不支持冒泡。与over与out的作用是相同的 [但是他们两个有兼容性问题,在老版本上]
    *
    *   - CSS:使用遮罩
    * */

    /*
    *
    * 使用:嵌套,并且子集有运动
    * */
<div id="mark"></div><!--后添加的优先级要高。他们中间隔了一层透明的层,所以无法触发-->

图片放大镜效果

苹果菜单

妙味照片墙

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,107评论 0 6
  • 1.背景介绍 什么是面向对象编程? “面向对象编程”(Object OrientedProgramming,缩写为...
    return_3711阅读 253评论 0 0
  • 你的思维格局决定你能走多远 今天看到了一个节目《一站到底》,节目中有一个来自哈佛大学的学霸,她休学回到北京创业。休...
    大_林子阅读 260评论 0 0
  • 事情并不是我认真我就输了,这是一直以来的一种误解,事实是我认真了你就输了,毕竟认真起来的我连自己都怕,毕竟认真的我...
    Skylt阅读 60评论 0 0
  • 我喜欢写作,这是没有疑问。大学四年,我喜欢把自己的想法一股脑写在笔记本上,10块钱一个的那种又大又厚的笔记本,写了...
    橙君阅读 330评论 0 1