JavaScript面向对象编程实战

来源:互联网 发布:淘宝卖家打折 编辑:程序博客网 时间:2024/05/23 20:30

转载地址http://blog.csdn.net/lmj623565791/article/details/34089553 

天重温了下Javacript,给大家带来一篇Javascript博文,相信对于Javacript有一定了解的人都听过prototype原型这个概念,今天我们深度的分析下prototype与__proto__。

好了,下面看一个非常简单的例子:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. var Person = function(name)  
  2.  {  
  3.      this.name = name ;  
  4.  };  
  5. var p = new Person("Ben");  
  6. console.log(p.name);  
代码简单的 你不用说明了,如果现在让大家根据上面的代码画一张包含Function与Object的内存图,大家肯定回想什么叫包含Function与Object,上面的代码和它们有几毛钱的关系。好了,下面我先按要求把图画出来,大家参考下:


解析下:

1、任何一个由构造器产生的对象都有__proto__属性,且此属性指向该构造器的prototype。

2、所有构造器/函数的__proto__都指向Function的prototype

拿第2条对比第1条,貌似我们发现了什么,没错函数的构造器就是Function,看下面的代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //函数表达式  
  2.     var Person = function(name)  
  3.     {  
  4.         this.name = name ;  
  5.     };  
  6.      //函数声明  
  7.      function Person(name)  
  8.      {  
  9.          this.name = name ;  
  10.      }  
  11.      //上面两种方式实际上就相当与new Function  
  12.      var Person = new Function("name" , "this.name = name ;" );  
当然了不能说说,下面看代码验证:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. console.log(Person.__proto__ === Function.prototype);  //true  
  2. console.log(typeof p.__proto__);//objcect  
  3. console.log(p.__proto__.__proto__ === Object.prototype); //true  

有人会问,那么Function与Object的prototype,__prop__到底是什么呢?

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. console.log(Object.__proto__ === Function.prototype); // true  
  2.    console.log(Function.__proto__ === Function.prototype); //true  
  3.    console.log(Function.prototype.__proto__ == Object.prototype); //true  
  4.    console.log(Object.prototype.__proto__); //null  


有此可见

1、所有的构造器包括Object和Function都继承了Function.prototype的方法,由第三行可知所有的构造器都是对象,即js中一切皆为对象。

2、__proto__最终的指向都是Object.prototype,这也就是js中的原型链。


最后我们看一下Object的文档:

Properties

The following table lists properties of the Object Object.

Property

Description

__proto__ Property

Specifies the prototype for an object.

constructor Property

Specifies the function that creates an object.

prototype Property

Returns a reference to the prototype for a class of objects.

发现Object还有个constructor属性。

1、constructor属性指向的是创建当前对象的构造函数。

2、每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数

看下面的例子:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //函数表达式  
  2.      var Person = function(name)  
  3.      {  
  4.          this.name = name ;  
  5.      };  
  6.   
  7.        var p = new Person("Ben");  
  8.   
  9.       console.log(p.constructor === Person);//true  
  10.       console.log(Person.prototype.constructor === Person);  //true  
  11.       console.log(Person.prototype instanceof  Object);  //true  
  12.       console.log(Person.prototype instanceof  Person);  //false  
  13.        //改变Person的prototype  
  14.       Person.prototype = {name:"123"} ;  
  15.       var p2 = new Person("Ben");  
  16.       console.log(p2.constructor === Object);//true  
  17.       console.log(p2.constructor === Person.prototype.constructor);//true  
  18.       console.log(Person.prototype.constructor === Object);//true  
  19.       console.log(Person.prototype.constructor === Person);//false  


当改变Person的prototype时,会发现,Person.prototype.constructor指向了Object,主要是因为:

Person.prototype = {name:"123"} 相当于Person.prototype=new Object({name:"123"} );此时的构造器变成了Object.



好了,就介绍到这里,各位看官没事留个言,赞一个,哈~。


 

Javascript 进阶 作用域 作用域链

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/25076713

一直觉得Js很强大,由于长期不写js代码,最近刚好温故温故。

1、Javascript没有代码块作用域的概念,局部作用域是针对函数来说的。

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. function fun()  
  2. {  
  3.     forvar i = 0 ; i < 10 ; i++)  
  4.     {}  
  5.     //如果在Java中i此时应当属于未声明的变量,但是Js中i的作用域依然存在  
  6.     console.log(i);//10  
  7.   
  8.     if(true)  
  9.     {  
  10.         var b = "helloworld";  
  11.     }  
  12.     console.log(b);//helloworld  
  13. }  
  14. fun();  


2、如果不使用var声明的变量,默认为全局变量

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. function fun02()  
  2. {  
  3.     a = "helloworld";  
  4.     var b = "welcome";  
  5. }  
  6. fun02();  
  7. console.log(a); //     helloworld  
  8. console.log(b); //   b is not defined  

3、Js中的作用域链

先看个简单的例子:只有一个函数对象,函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. var a = "hello";  
  2.   
  3.       function fun04()  
  4.       {  
  5.            a = "world";  
  6.             var b ="welcome";  
  7.       }  
作用域链的图:


注:图中省略了,Global Scope中的window,document等,每个函数对象中的arguments,this等均未画出。

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. function fun03()  
  2.       {  
  3.           var a = 10;  
  4.           return function(){  
  5.               a*= 2 ;  
  6.               return a ;  
  7.           };  
  8.       }  
  9.   
  10.       var f = fun03();  
  11.       f();  
  12.       var x = f();  
  13.      console.log(x);  //40  
  14.   
  15.       var g = fun03();  
  16.       var y = g();  
  17.       console.log(y); //20  

观察上面代码,存在fun03,f,g三个函数对象。

下面是作用域链的图:


注:每个函数对象一个作用域链,这里直接画在了一起;对于变量的查找,先从链的0开始找。

函数对象 f 在代码中执行了2 次,所以a*2*2 = 40 ; 函数对象 g 在代码中执行了1次, 所以 a *2 = 20 ; 

4、闭包

上面的例子可以看到,在fun03执行完成后,a的实例并没有被销毁,这就是闭包。个人对闭包的理解是:函数执行完成后,函数中的变量没有被销毁,被它返回的子函数所引用。

下面以一个特别经典的例子,同时使用作用域链解析:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. window.onload = function()  
  2.         {  
  3.             var elements = document.getElementsByTagName("li");  
  4.             for(var i = 0; i < elements.length ; i ++)  
  5.             {  
  6.                 elements[i].onclick = function()  
  7.                 {  
  8.                     alert(i);  
  9.                 }  
  10.             }  
  11.   
  12.         }  

相信上面的代码肯定大家都写过,本意是点击每个li,打印出它们的索引,可是事实上打印出的都是elements.length。这是为什么呢?


看下上面的简易的作用域链(省略了很多部分,主要是理解),此时每个onclick函数的i,指向的都是 onload 中的i 此时的 i = element.length.

下面看解决方案:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. window.onload = function ()  
  2.        {  
  3.            var elements = document.getElementsByTagName("li");  
  4.            for (var i = 0; i < elements.length; i++)  
  5.            {  
  6.                (function (n)  
  7.                {  
  8.                    elements[n].onclick = function ()  
  9.                    {  
  10.                        alert(n);  
  11.                    }  
  12.                })(i);  
  13.            }  
  14.   
  15.        }  

在onclick函数的外层,包了一层立即执行的函数,所以此时的n指向的 n 是立即执行的,所有都是1~elements.length 。 

Javascript 进阶 封装

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/25080573

js中处处是对象,面向对象的第一步当然就是封装了,由于Js中没有类的概念,所以封装起来也比较麻烦,下面介绍两种js的封装。

1、使用约定优先的原则,将所有的私有变量以_开头

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.        /** 
  3.         * 使用约定优先的原则,把所有的私有变量都使用_开头 
  4.         */  
  5.        var Person = function (no, name, age)  
  6.        {  
  7.            this.setNo(no);  
  8.            this.setName(name);  
  9.            this.setAge(age);  
  10.        }  
  11.        Person.prototype = {  
  12.            constructor: Person,  
  13.            checkNo: function (no)  
  14.            {  
  15.                if (!no.constructor == "string" || no.length != 4)  
  16.                    throw new Error("学号必须为4位");  
  17.            },  
  18.            setNo: function (no)  
  19.            {  
  20.                this.checkNo(no);  
  21.                this._no = no;  
  22.            }, getNo: function ()  
  23.            {  
  24.                return this._no;  
  25.            }, setName: function (name)  
  26.            {  
  27.                this._name = name;  
  28.            }, getName: function ()  
  29.            {  
  30.                return this._name;  
  31.            }, setAge: function (age)  
  32.            {  
  33.                this._age = age;  
  34.            }, getAge: function ()  
  35.            {  
  36.                return this._age;  
  37.            }, toString: function ()  
  38.            {  
  39.                return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;  
  40.            }  
  41.        };  
  42.        var p1 = new Person("0001""鸿洋""22");  
  43.        console.log(p1.toString());        //no = 0001 , name = 鸿洋 , age = 22  
  44.        p1.setNo("0003");  
  45.        console.log(p1.toString());      //no = 0003 , name = 鸿洋 , age = 22  
  46.        p1.no = "0004";  
  47.        p1._no = "0004";  
  48.        console.log(p1.toString());    //no = 0004 , name = 鸿洋 , age = 22  
  49.   
  50.    </script>  

看完代码,是不是有种被坑的感觉,仅仅把所有的变量以_开头,其实还是可以直接访问的,这能叫封装么,当然了,说了是约定优先嘛,这种方式还是不错的,最起码成员变量的getter,setter方法都是prototype中,并非存在对象中,总体来说还是个不错的选择。如果你觉得,这不行,必须严格实现封装,那么看第二种方式。

2、严格实现封装

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.         /** 
  3.          *  使用这种方式虽然可以严格实现封装,但是带来的问题是get和set方法都不能存储在prototype中,都是存储在对象中的 
  4.          * 这样无形中就增加了开销 
  5.          */  
  6.         var Person = function (no, name, age)  
  7.         {  
  8.             var _no , _name, _age ;  
  9.             var checkNo = function (no)  
  10.             {  
  11.                 if (!no.constructor == "string" || no.length != 4)  
  12.                     throw new Error("学号必须为4位");  
  13.             };  
  14.             this.setNo = function (no)  
  15.             {  
  16.                 checkNo(no);  
  17.                 _no = no;  
  18.             };  
  19.             this.getNo = function ()  
  20.             {  
  21.                 return _no;  
  22.             }  
  23.             this.setName = function (name)  
  24.             {  
  25.                _name = name;  
  26.             }  
  27.   
  28.             this.getName = function ()  
  29.             {  
  30.                 return _name;  
  31.             }  
  32.   
  33.             this.setAge = function (age)  
  34.             {  
  35.                 _age = age;  
  36.             }  
  37.             this.  
  38.                     getAge = function ()  
  39.             {  
  40.                 return _age;  
  41.             }  
  42.   
  43.             this.setNo(no);  
  44.             this.setName(name);  
  45.             this.setAge(age);  
  46.         }  
  47.         Person.prototype = {  
  48.             constructor: Person,  
  49.             toString: function ()  
  50.             {  
  51.                 return "no = " + this.getNo() + " , name = " + this.getName() + " , age = " + this.getAge();  
  52.             }  
  53.         }  
  54.         ;  
  55.         var p1 = new Person("0001""鸿洋""22");  
  56.         console.log(p1.toString());        //no = 0001 , name = 鸿洋 , age = 22  
  57.         p1.setNo("0003");  
  58.         console.log(p1.toString());      //no = 0003 , name = 鸿洋 , age = 22  
  59.         p1.no = "0004";  
  60.         console.log(p1.toString());    //no = 0003 , name = 鸿洋 , age = 22  
  61.   
  62.     </script>  

看上面的代码,去掉了this.属性名,严格的实现了封装,只能通过getter,setter访问成员变量了,但是存在一个问题,所有的方法都存在对象中,增加了内存的开销。

3、以闭包的方式封装

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.         /** 
  3.          *  使用这种方式虽然可以严格实现封装,但是带来的问题是get和set方法都不能存储在prototype中,都是存储在对象中的 
  4.          * 这样无形中就增加了开销 
  5.          */  
  6.         var Person = (function ()  
  7.         {  
  8.             var checkNo = function (no)  
  9.             {  
  10.                 if (!no.constructor == "string" || no.length != 4)  
  11.                     throw new Error("学号必须为4位");  
  12.             };  
  13.             //共享变量  
  14.             var times = 0;  
  15.   
  16.             return function (no, name, age)  
  17.             {  
  18.                 console.log(times++);    // 0 ,1 , 2  
  19.                 var no , name , age;  
  20.                 this.setNo = function (no)  
  21.                 {  
  22.                     checkNo(no);  
  23.                     this._no = no;  
  24.                 };  
  25.                 this.getNo = function ()  
  26.                 {  
  27.                     return this._no;  
  28.                 }  
  29.                 this.setName = function (name)  
  30.                 {  
  31.                     this._name = name;  
  32.                 }  
  33.   
  34.                 this.getName = function ()  
  35.                 {  
  36.                     return this._name;  
  37.                 }  
  38.   
  39.                 this.setAge = function (age)  
  40.                 {  
  41.                     this._age = age;  
  42.                 }  
  43.                 this.  
  44.                         getAge = function ()  
  45.                 {  
  46.                     return this._age;  
  47.                 }  
  48.   
  49.                 this.setNo(no);  
  50.                 this.setName(name);  
  51.                 this.setAge(age);  
  52.             }  
  53.         })();  
  54.         Person.prototype = {  
  55.             constructor: Person,  
  56.             toString: function ()  
  57.             {  
  58.                 return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;  
  59.             }  
  60.         }  
  61.         ;  
  62.         var p1 = new Person("0001""鸿洋""22");  
  63.         var p2 = new Person("0002""abc""23");  
  64.         var p3 = new Person("0003""aobama""24");  
  65.   
  66.   
  67.         console.log(p1.toString());        //no = 0001 , name = 鸿洋 , age = 22  
  68.         console.log(p2.toString());      //no = 0002 , name = abc , age = 23  
  69.         console.log(p3.toString());    //no = 0003 , name = aobama , age = 24  
  70.   
  71.     </script>  

上述代码,js引擎加载完后,会直接执行Student = 立即执行函数,然后此函数返回了一个子函数,这个子函数才是new Student所调用的构造函数,又因为子函数中保持了对立即执行函数中checkNo(no) ,times的引用,(很明显的闭包)所以对于checkNo和times,是所有Student对象所共有的,创建3个对象后,times分别为0,1,2 。这种方式的好处是,可以使Student中需要复用的方法和属性做到私有且对象间共享。 

Javascript 进阶 继承

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/29194261

1、基于类的继承
下面看下面的代码:
[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1.  <script type="text/javascript">  
  2.   
  3.   
  4.         function Person(name, age)  
  5.         {  
  6.             this.name = name;  
  7.             this.age = age;  
  8.         }  
  9.         Person.prototype.say = function ()  
  10.         {  
  11.             console.log(this.name + " , " + this.age);  
  12.         }  
  13.         function Student(no)  
  14.         {  
  15.             this.no = no;  
  16.         }  
  17. <span style="white-space:pre">    /** 
  18.          * Student的prototype指向Person的对象 
  19.          */</span>  
  20.         Student.prototype = new Person();  
  21.         var stu1 = new Student("0001");  
  22.         stu1.name = '张三';  
  23.         stu1.age = '11';  
  24.         console.log(stu1.no);  
  25.         stu1.say();  
  26.   
  27.   
  28.     </script>  

输出结果:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 0001   
  2. 张三 , 11   

可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:


将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。

但是这种方式存在问题:

问题1:当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.        /** 
  3.         * 存在问题 
  4.         * 1、无法在Student的构造方法中传递参数用于父类的构造方法 
  5.         * 2、对于引用类型变量,造成数据不一致 
  6.         */  
  7.   
  8.   
  9.        function Person(name, age)  
  10.        {  
  11.            this.name = name;  
  12.            this.age = age;  
  13.            this.hobbies = [] ;  
  14.        }  
  15.        Person.prototype.say = function ()  
  16.        {  
  17.            console.log(this.name + " , " + this.age +" , " +this.hobbies);  
  18.        }  
  19.        function Student(no)  
  20.        {  
  21.            this.no = no;  
  22.        }  
  23.        Student.prototype = new Person();  
  24.   
  25.        var stu1 = new Student("0001");  
  26.        stu1.name = '张三';  
  27.        stu1.age = '11';  
  28.        stu1.hobbies.push("soccer");  
  29.        stu1.say();  
  30.   
  31.        var stu2 = new Student("0002");  
  32.        stu2.name = '李四';  
  33.        stu2.age = '12';  
  34.        stu2.hobbies.push("girl");  
  35.        stu2.say();  
  36.   
  37.    </script>  

输出结果:
[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 张三 , 11 , soccer   
  2. 李四 , 12 , soccer,girl   
可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。

上述的继承方式还存在一个问题:

问题2:在Student的构造方法中,无法使用new Student("00001" , "张三" , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值


为了解决上述问题,对上述代码进行修改:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.   
  3.        function Person(name, age)  
  4.        {  
  5.            this.name = name;  
  6.            this.age = age;  
  7.            this.hobbies = [];  
  8.        }  
  9.        Person.prototype.say = function ()  
  10.        {  
  11.            console.log(this.name + " , " + this.age +" , " + this.hobbies);  
  12.        }  
  13.   
  14.        function Student(name, age, no)  
  15.        {  
  16.            /** 
  17.             * 使用call方法,第一个参数为上下文; 
  18.             * 有点类似Java中的super(name,age)的感觉 
  19.             */  
  20.            Person.call(this, name, age);  
  21.            this.no = no;  
  22.        }  
  23.   
  24.        Student.prototype = new Person();  
  25.   
  26.        var stu1 = new Student("0001","张三",11);  
  27.        stu1.hobbies.push("soccer");  
  28.        stu1.say();  
  29.   
  30.        var stu2 = new Student("0002","李四",12);  
  31.        stu2.hobbies.push("cangjin");  
  32.        stu2.hobbies.push("basketball");  
  33.        stu2.say();  
  34.   
  35.    </script>  

输出:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 0001 , 张三 , soccer   
  2. 0002 , 李四 , cangjin,basketball   

在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。

2、基于原型链的继承

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.   
  3.     /** 
  4.      * 基于原型链的集成中都是对象 
  5.      * 存在问题: 
  6.      * 1、对于引用类型变量,造成数据不一致 
  7.      */  
  8.     var Person = {  
  9.                 name: "人",  
  10.                 age: 0,  
  11.                 hobbies: [],  
  12.                 say: function ()  
  13.                 {  
  14.                     console.log(this.name + " , " + this.age + " , " + this.hobbies);  
  15.                 }  
  16.             }  
  17.             ;  
  18.   
  19.     var Student = clone(Person);  
  20.     Student.no ="";  
  21.     Student.sayHello = function()  
  22.     {  
  23.         console.log(this.name  +"hello ") ;  
  24.     }  
  25.   
  26.     var stu1 = clone(Student);  
  27.     stu1.name = "zhangsan";  
  28.     stu1.age = 12;  
  29.     stu1.hobbies.push("Java");  
  30.     stu1.say();  
  31.   
  32.     var stu2 = clone(Student);  
  33.     stu2.name = "lisi";  
  34.     stu2.age = 13;  
  35.     stu2.hobbies.push("Javascript");  
  36.     stu2.say();  
  37.   
  38.     /** 
  39.      * 返回一个prototype执行obj的一个对象 
  40.      * @param obj 
  41.      * @returns {F} 
  42.      */  
  43.     function clone(obj)  
  44.     {  
  45.         var F = function ()  
  46.         {  
  47.         };  
  48.         F.prototype = obj;  
  49.         return new F();  
  50.   
  51.     }  
  52.   
  53.   
  54. </script>  

输出:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. zhangsan , 12 , Java   
  2. lisi , 13 , Java,Javascript   

可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:


对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。


好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。



如果代码或者讲解存在任何问题,欢迎留言指出。

 

Javascript 进阶 面向对象编程 继承的一个例子

Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承。

1、利用面向对象的写法,实现下面这个功能,实时更新数据的一个例子:



2、使用对上面类的继承,完成下面的效果:


好了,不多说,js的训练全靠敲,所以如果觉得面向对象不是很扎实,可以照着敲一个,如果觉得很扎实了,提供了效果图,可以自己写试试。

1、第一个效果图代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 14-6-7 
  5.  * Time: 下午4:55 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8. /** 
  9.  * @param id 
  10.  * @param value 
  11.  * @param parentEle 父元素 
  12.  * @constructor 
  13.  */  
  14. function PlaceFieldEditor(id, value, parentEle)  
  15. {  
  16.     this.id = id;  
  17.     this.value = value;  
  18.     this.parentEle = parentEle;  
  19.     this.initValue = value ;  
  20.   
  21.     this.initElements();  
  22.     this.initEvents();  
  23. }  
  24.   
  25. PlaceFieldEditor.prototype = {  
  26.     constructor: PlaceFieldEditor,  
  27.     /** 
  28.      * 初始化所有元素 
  29.      */  
  30.     initElements: function ()  
  31.     {  
  32.         this.txtEle = $("<span/>");  
  33.         this.txtEle.text(this.value);  
  34.   
  35.         this.textEle = $("<input type='text' />");  
  36.         this.textEle.val(this.value);  
  37.   
  38.         this.btnWapper = $("<div style='display: inline;'/>");  
  39.         this.saveBtn = $("<input type='button' value='保存'/>");  
  40.         this.cancelBtn = $("<input type='button' value='取消'/>");  
  41.         this.btnWapper.append(this.saveBtn).append(this.cancelBtn);  
  42.   
  43.         this.parentEle.append(this.txtEle).append(this.textEle).append(this.btnWapper);  
  44.   
  45.         this.convertToReadable();  
  46.     },  
  47.     /** 
  48.      * 初始化所有事件 
  49.      */  
  50.     initEvents: function ()  
  51.     {  
  52.         var that = this;  
  53.         this.txtEle.on("click"function (event)  
  54.         {  
  55.             that.convertToEditable();  
  56.         });  
  57.   
  58.         this.cancelBtn.on("click"function (event)  
  59.         {  
  60.             that.cancel();  
  61.         });  
  62.   
  63.         this.saveBtn.on("click"function (event)  
  64.         {  
  65.             that.save();  
  66.         });  
  67.   
  68.     },  
  69.     /** 
  70.      * 切换到编辑模式 
  71.      */  
  72.     convertToEditable: function ()  
  73.     {  
  74.         this.txtEle.hide();  
  75.         this.textEle.show();  
  76.         this.textEle.focus();  
  77.   
  78.         if(this.getValue() == this.initValue )  
  79.         {  
  80.             this.textEle.val("");  
  81.         }  
  82.   
  83.         this.btnWapper.show();  
  84.     },  
  85.     /** 
  86.      * 点击保存 
  87.      */  
  88.     save: function ()  
  89.     {  
  90.         this.setValue(this.textEle.val());  
  91.         this.txtEle.html(this.getValue().replace(/\n/g,"<br/>"));  
  92.   
  93.         var url = "id=" + this.id + "&value=" + this.value;  
  94. //                alert(url);  
  95.         console.log(url);  
  96.         this.convertToReadable();  
  97.     },  
  98.     /** 
  99.      * 点击取消 
  100.      */  
  101.     cancel: function ()  
  102.     {  
  103.         this.textEle.val(this.getValue());  
  104.         this.convertToReadable();  
  105.     },  
  106.     /** 
  107.      * 切换到查看模式 
  108.      */  
  109.     convertToReadable: function ()  
  110.     {  
  111.         this.txtEle.show();  
  112.         this.textEle.hide();  
  113.         this.btnWapper.hide();  
  114.     },  
  115.     setValue: function (value)  
  116.     {  
  117.         this.value = value;  
  118.     },  
  119.     getValue: function ()  
  120.     {  
  121.         return this.value;  
  122.     }  
  123. }  
  124. ;  

引入到页面代码:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  
  2.         "http://www.w3.org/TR/html4/loose.dtd">  
  3. <html>  
  4. <head>  
  5.     <title></title>  
  6.     <script type="text/javascript" src="jquery-1.8.3.js"></script>  
  7.     <script type="text/javascript" src="PlaceFieldEditor.js"></script>  
  8.   
  9.     <script type="text/javascript">  
  10.         $(function ()  
  11.         {  
  12.   
  13.             $("ul li").each(function ()  
  14.             {  
  15.                 new PlaceFieldEditor($(this).attr("id"), "请输出成绩...", $(this));  
  16.             });  
  17.   
  18.   
  19.         });  
  20.   
  21.     </script>  
  22.   
  23.     <style type="text/css">  
  24.         body  
  25.         {  
  26.             font-size: 12px;  
  27.             color: #333;;  
  28.         }  
  29.   
  30.         ul li  
  31.         {  
  32.             line-height: 30px;  
  33.         }  
  34.   
  35.     </style>  
  36. </head>  
  37. <body>  
  38.   
  39.   
  40. <ul>  
  41.     <li id="1">张三:</li>  
  42.     <li id="2">李四:</li>  
  43.     <li id="3">王二:</li>  
  44. </ul>  
  45.   
  46. </body>  
  47. </html>  
嗯,代码就不详细说了,都比较简单,使用了jQuery,如果不喜欢可以使用原生js,本人比较喜欢把jQuery当作js的工具使用。


2、第二个效果图的js代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 14-6-7 
  5.  * Time: 下午5:34 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8. function PlaceAreaEditor(id, value, parentEle)  
  9. {  
  10.     PlaceAreaEditor.superClass.constructor.call(this, id, value, parentEle);  
  11. }  
  12.   
  13. extend(PlaceAreaEditor, PlaceFieldEditor);  
  14.   
  15. PlaceAreaEditor.prototype.initElements = function ()  
  16. {  
  17.     this.txtEle = $("<span/>");  
  18.     this.txtEle.text(this.value);  
  19.   
  20.     this.textEle = $("<textarea style='width:315px;height:70px;' />");  
  21.     this.textEle.text(this.value);  
  22.   
  23.     this.btnWapper = $("<div style='display: block;'/>");  
  24.     this.saveBtn = $("<input type='button' value='保存'/>");  
  25.     this.cancelBtn = $("<input type='button' value='取消'/>");  
  26.     this.btnWapper.append(this.saveBtn).append(this.cancelBtn);  
  27.   
  28.     this.parentEle.append(this.txtEle).append(this.textEle).append(this.btnWapper);  
  29.   
  30.     this.convertToReadable();  
  31.   
  32. };  

写了PlaceAreaEditor继承了PlaceFieldEditor,然后复写了initElements方法,改变了text为textarea。

extend的方法,上一篇博客已经介绍过:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * @param subClass  子类 
  3.  * @param superClass   父类 
  4.  */  
  5. function extend(subClass, superClass)  
  6. {  
  7.     var F = function ()  
  8.     {  
  9.     };  
  10.     F.prototype = superClass.prototype;  
  11.     //子类的prototype指向F的_proto_ , _proto_又指向父类的prototype  
  12.     subClass.prototype = new F();  
  13.     //在子类上存储一个指向父类的prototype的属性,便于子类的构造方法中与父类的名称解耦 使用subClass.superClass.constructor.call代替superClass.call  
  14.     subClass.superClass = superClass.prototype;  
  15. }  
最后页面代码:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  
  2.         "http://www.w3.org/TR/html4/loose.dtd">  
  3. <html>  
  4. <head>  
  5.     <title></title>  
  6.     <script type="text/javascript" src="jquery-1.8.3.js"></script>  
  7.     <script type="text/javascript" src="PlaceFieldEditor.js"></script>  
  8.     <script type="text/javascript" src="com.zhy.extend.utils.js"></script>  
  9.     <script type="text/javascript" src="PlaceAreaEditor.js"></script>  
  10.   
  11.     <script type="text/javascript">  
  12.   
  13.         $(function ()  
  14.         {  
  15.             $("ul li div").each(function ()  
  16.             {  
  17.                 new PlaceAreaEditor($(this).attr("id"), "请留言...", $(this));  
  18.             });  
  19.         });  
  20.   
  21.     </script>  
  22.   
  23.     <style type="text/css">  
  24.   
  25.         body  
  26.         {  
  27.             font-size: 12px;  
  28.             color: #333;;  
  29.         }  
  30.   
  31.         ul li  
  32.         {  
  33.             padding: 5px 0 8px 0 ;  
  34.         }  
  35.   
  36.     </style>  
  37. </head>  
  38. <body>  
  39.   
  40.   
  41. <ul>  
  42.     <li id="1"><h3>我要改剧本,不让~~</h3>  
  43.         <div>  
  44.         </div>  
  45.     </li>  
  46.   
  47.     <li id="2"><h3>悬崖上有桥么,有?没有~ </h3>  
  48.         <div>  
  49.         </div>  
  50.     </li>  
  51.     <li id="3"><h3>你敢打坏我的灯?不租~   </h3>  
  52.         <div>  
  53.         </div>  
  54.     </li>  
  55. </ul>  
  56.   
  57. </body>  
  58. </html>  



好了,结束~~ 上面的例子是根据孔浩老师的例子修改的,感谢孔浩老师,孔老师地址:www.konghao.org。孔老师录制了很多Java相关视频,有兴趣的可以去他网站学习!


代码或者讲解有任何问题,欢迎留言指出。

 

Javascript 设计模式 单例

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/30490955

一直很喜欢Js,,,今天写一个Js的单例模式实现以及用法。

1、单例模式的写法

单例模式写法相当简单:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. var singleTon = {  
  2.        m1: "memeber first ",  
  3.        m2: "memeber second ",  
  4.        f1: function ()  
  5.        {  
  6.            console.log("fun1 ");  
  7.        }  
  8.    };  

好了,结束了,其实就是字面量创建对象的方式,很简单吧。如果你觉得单例太简单,不用看了,那你就错了,单例在Js中用的地方挺多,话说你经常用么~。

2、单例用法一:创建命名空间

在开发中一个页面一般会引入多个Js文件,甚至这多个文件多人写的,大家都可能在全局定义init这个方法,都可能在全局声明name这是属性。这样的话就造成的命名的冲突,发生一些意想不到的问题。所以我们需要引入命名空间:

我们可以让每个程序猿写的Js在他自己的命名空间下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 创建命名空间 
  3.  * @type {{}} 
  4.  */  
  5. var ZhangHongYang = {};  
  6.   
  7. var zhy = {};  
  8. zhy.com = {} ;  
  9. zhy.com.js = {};  

比如以每个人的名字作为命名空间,之后写方法就:ZhangHongyang.xxx();或者你习惯了Java的命名空间,也可以zhy.com.js.xxx。

3、单例实例:实现一个注册页面的Js

针对像注册页面上的Js,一般都是针对此页面写的,建议使用单例的方式书写。

下面的展示如何使用单例的写法,实现ajax的注册功能,当然没有服务器,模拟一下:

html:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <body>  
  2. <form action="user/register" id="registerForm">  
  3.   
  4.     <div>  
  5.         <label for="username">username</label>  
  6.         <input type="text" name="username" id="username"/>  
  7.     </div>  
  8.     <div>  
  9.         <label for="nickname">nickname</label>  
  10.         <input type="text" name="nickname" id="nickname"/>  
  11.     </div>  
  12.     <div>  
  13.         <label for="password">password</label>  
  14.         <input type="text" name="password" id="password"/>  
  15.     </div>  
  16.   
  17.     <div>  
  18.         <input type="submit" value="Register"/>  
  19.     </div>  
  20. </form>  
  21.   
  22. <div id="registerResult" style="width: 400px;height: 200px;border: 1px solid #444;">  
  23.   
  24. </div>  
  25.   
  26.   
  27. </body>  

当用户点击submit,会进行一些列的处理,最终将数据展示到registerResult中:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.   
  3.        /** 
  4.         * 单例的用法: 
  5.         * 有时候我们需要针对某个页面进行写Js,比如登录页面,建议使用下列方式: 
  6.         * ZhangHongyang,singlePageJsForRegiste = 
  7.         * { 
  8.         *     CONSTANT1:"", 
  9.         *     CONSTANT2:"", 
  10.         *     f1:function(){}, 
  11.         *     f2:function(){} 
  12.         * } 
  13.         */  
  14.   
  15.        ZhangHongYang.singlePageJsForRegister =  
  16.        {  
  17.            ID_FROM: "registerForm",  
  18.            ID_RESULT_CONTAINER: "registerResult",  
  19.            init: function ()  
  20.            {  
  21.                ZhangHongYang.singlePageJsForRegister.form = $("#" + this.ID_FROM);  
  22.                ZhangHongYang.singlePageJsForRegister.result = $("#" + ZhangHongYang.singlePageJsForRegister.ID_RESULT_CONTAINER);  
  23.                this.form.submit(this.handleSubmit);  
  24.            },  
  25.            handleSubmit: function (event)  
  26.            {  
  27.   
  28.                var datas = {};  
  29.                ZhangHongYang.singlePageJsForRegister.form.find("input").each(function (i)  
  30.                {  
  31.                    //omitted the unnecessary datas  
  32.                    if (!($(this).attr("type") == "button" || $(this).attr("type") == "submit" || $(this).attr("type") == "reset" ))  
  33.                    {  
  34.                        datas[$(this).attr("name")] = $(this).val();  
  35.                    }  
  36.                });  
  37.                ZhangHongYang.singlePageJsForRegister.ajaxSubmit(datas);  
  38.                //prevent the default form submit  
  39.                event.preventDefault();  
  40.            },  
  41.            ajaxSubmit: function (datas)  
  42.            {  
  43.                var url = ZhangHongYang.singlePageJsForRegister.form.attr("action");  
  44.                console.log("url :" + url);  
  45.                //make ajax submit here  
  46.                //$.post(url,datas,function(data){});  
  47.                //show result  
  48.                ZhangHongYang.singlePageJsForRegister.showResult(datas);  
  49.            },  
  50.            showResult: function (datas)  
  51.            {  
  52.                var result = "";  
  53.                for (var p in datas)  
  54.                {  
  55.                    result += p + " = " + datas[p] + "<br/>";  
  56.                }  
  57.                ZhangHongYang.singlePageJsForRegister.result.html(result);  
  58.            }  
  59.        };  
  60.   
  61.        $(function ()  
  62.        {  
  63.            ZhangHongYang.singlePageJsForRegister.init();  
  64.        });  
  65.   
  66.   
  67.    </script>  

我们使用单例定义了一个singlePageJsForRegister方法对象,然后将需要用到的元素的Id作为了常量,然后通过init初始化事件等,还有其他的几个函数,代码中也书写了注释。看了上面的代码可能觉得这么写好复杂,代码量也多了,但是对于Js的提升,要慢慢的学习面向对象以及结构化的写法,不能在script标签中,不断的定义各种方法,甚至在html标签中书写onclick这类的属性。Js一定要保证,html与js文件解耦;js代码整体上结构清晰;学习使用面向对象的方式处理问题。



4、如何在单例创建的对象中,定义私有方法和属性

上述单例的写法,会把所有的方法与变量暴露给使用者, 如何设置私有变量或者私有方法。

a、采用约定的方式:所有以_开头的方法和变量都是私有变量。

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.        * 方式一 
  3.        * 采用约定,所有以_开头的变量或者方法为私有变量 
  4.        */  
  5.       var singleTon = {  
  6.           _m1: "hello",  
  7.           _f1: function ()  
  8.           {  
  9.           },  
  10.           init: function ()  
  11.           {  
  12.           }  
  13.       };  

可以觉得方式1不是自己骗自己么,但是项目嘛,约定由于配置,也是可行的。实在觉得不能忍受,看方式二:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.         * 方式二 
  3.         */  
  4.        var singleTon = (function ()  
  5.        {  
  6.            var _m1 = "hello";  
  7.            var _f1 = function ()  
  8.            {  
  9.                console.log(" i am a private function !");  
  10.            }  
  11.   
  12.            return {  
  13.                //public method  
  14.                init: function ()  
  15.                {  
  16.                    //invoke the private method in the singleTon  
  17.                    _f1();  
  18.                }  
  19.            };  
  20.   
  21.        })();  

采用了闭包的方式,很好的实现了私有变量和私有方法的隐藏。

5、单例实例:解决Textarea的数据存储时的Html转Txt和展示时Txt转Html

在web项目中,很多情况会使用到Textarea。

a、比如留言、技能的书写等;对于这类Textarea我们有必要对用户输入的html代码做特殊处理,防止用户填写恶意代码或者把页面的样式弄乱。

b、相反来说,在Textarea中书写的换行以及空格,最终在div中显示却没有效果,都是一个空格,所有很多web开发者会选择使用只读textarea来回显用户输入内容,其实需要做一定的转换。

html:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <body>  
  2. <textarea style="width: 400px;height: 120px;" id="taContent">  
  3. </textarea>  
  4.   
  5. <input type="button" id="convert" value="Convert"/>  
  6. <br/>  
  7. <br/>  
  8.   
  9.   
  10. <fieldset style="width: 400px">  
  11.     <legend>html转化为Txt,供Div展示</legend>  
  12. <div style="width: 400px;height: 120px;border: 1px solid #555;" id="divContent">  
  13.   
  14. </div>  
  15. </fieldset>  
  16.   
  17. <br/>  
  18. <br/>  
  19.   
  20. <fieldset style="width: 400px">  
  21.     <legend>Txt转化为Html,供Textarea修改</legend>  
  22.     <textarea style="width: 400px;height: 120px;" id="taEdit">  
  23.     </textarea>  
  24. </fieldset>  
  25.   
  26. </body>  

第一个Textarea用于用户输入,然后经过转义显示到div中,然后将转义后的数据进行逆向恢复显示到第二个TextArea中。相当与模拟了,div中展示数据和用户再次编辑数据,这些功能在项目中都相当实用。

我们的js代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.        * 对用户在TextArea中输入的数据进行过滤,把< -> <等操作,以及逆向操作 
  3.        */  
  4.       ZhangHongYang.htmlFilter = (function ()  
  5.       {  
  6.           /** 
  7.            * 转化textarea中的空格为$nbsp; 
  8.            * \n转化为<br/> 
  9.            * @private 
  10.            */  
  11.           function _transSpace(data)  
  12.           {  
  13.               return data.replace(/\n/g, "<br/>").replace(/\s/g, " ");  
  14.           };  
  15.   
  16.           /** 
  17.            * 转化所有尖括号 
  18.            * @private 
  19.            */  
  20.           function _transBrace(data)  
  21.           {  
  22.               return data.replace(/</g, "<").replace(/>/g, ">");  
  23.           };  
  24.   
  25.   
  26.           function _resumeSpace(data)  
  27.           {  
  28.               return data.replace(/ /g, " ").replace(/<br\s*\/>/ig, "\n");  
  29.           };  
  30.           function _resumeBrace(data)  
  31.           {  
  32.               return data.replace(/</g, "<").replace(/>/g, ">");  
  33.           };  
  34.   
  35.           return {  
  36.   
  37.               txt2Html: function (data)  
  38.               {  
  39.                   return _transSpace(_transBrace(data));  
  40.   
  41.               }, html2Txt: function (data)  
  42.               {  
  43.                   return _resumeSpace(_resumeBrace(data));  
  44.               }  
  45.           };  
  46.   
  47.       })();  

在我的命名空间下定义了htmlFilter方法,然后最后暴露两个方法Html2Txt和Txt2Html给使用者。

调用的代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.     $(function ()  
  3.     {  
  4.         $("#convert").click(function ()  
  5.         {  
  6.             var txt = ZhangHongYang.htmlFilter.txt2Html($("#taContent").val());  
  7.             console.log(txt);  
  8.             $("#divContent").html(txt);  
  9.             $("#taEdit").val(ZhangHongYang.htmlFilter.html2Txt(txt));  
  10.         });  
  11.     });  
  12. </script>  

效果图:


可以看到换行、空格、以及恶意的HTML代码等都得到了很好的在DIV中的显示;且最终可还原为Textarea中供编辑;如果各位项目中没有考虑到这类问题,首先你可以测试下问题,然后可以使用上面的代码解决这类问题。

6、单例写法提高多分支代码效率

相信大家都了解过ajax,对象ajax肯定离不开XMLHttpRequest,而且不同版本、类型的浏览器创建方式不一致。一般我们可能会这么写创建XMLHttpRequest的方法:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. function createXhr()  
  2.       {  
  3.           var xmlhttp;  
  4.           if (window.XMLHttpRequest)  
  5.           {// code for IE7+, Firefox, Chrome, Opera, Safari  
  6.               xmlhttp=new XMLHttpRequest();  
  7.           }  
  8.           else  
  9.           {// code for IE6, IE5  
  10.               xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");  
  11.           }  
  12.   
  13.           return xmlhttp ;  
  14.       }  

存在一个问题,每次创建XHR对象都需要进行分支判断,如果某个方法分支特别多,我们可以做进一步的优化,当浏览器加载js文件时,就决定以后调用只会用其中合适的方式,而不会走分支。

我们把代码改成:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.       * 用于在程序加载次js文件时,根据当前浏览器返回一个创建xhr的工厂方法,而不需要每次都去分支判断 
  3.       */  
  4.      ZhangHongYang.xhrFactroy = (function ()  
  5.      {  
  6.          function _ieCreateXhr()  
  7.          {     // code for IE6, IE5  
  8.              return   new ActiveXObject("Microsoft.XMLHTTP");  
  9.          }  
  10.   
  11.          function _newCreateXhr()  
  12.          {  
  13.              // code for IE7+, Firefox, Chrome, Opera, Safari  
  14.              return new XMLHttpRequest();  
  15.          }  
  16.   
  17.          if (window.XMLHttpRequest)  
  18.          {  
  19.              return _newCreateXhr;  
  20.          }  
  21.          else  
  22.          {  
  23.              return _ieCreateXhr;  
  24.          }  
  25.      })();  

当程序加载完成js文件后,会自动根据浏览器类型返回适合的方法,避免每次都会进行分支判断,我们只需要使用ZhangHongYang.xhrFactroy();创建XHR对象。

7、单例引入懒加载功能

上述的js的文件基本在引入页面后,浏览器加载就会进行大量操作占用内存,有时候我们希望等到我们去使用时再去执行一些操作,如果从未使用就省去不必要的内存消耗,我们可以进行如下改写代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.          * 用于在程序加载次js文件时,根据当前浏览器返回一个创建xhr的工厂方法,而不需要每次都去分支判断 
  3.          */  
  4.         ZhangHongYang.xhrFactroy = (function ()  
  5.         {  
  6.             var _instance = null;  
  7.   
  8.             function _constructor()  
  9.             {  
  10.                 function _ieCreateXhr()  
  11.                 {     // code for IE6, IE5  
  12.                     return   new ActiveXObject("Microsoft.XMLHTTP");  
  13.                 }  
  14.   
  15.                 function _newCreateXhr()  
  16.                 {  
  17.                     // code for IE7+, Firefox, Chrome, Opera, Safari  
  18.                     return new XMLHttpRequest();  
  19.                 }  
  20.   
  21.                 if (window.XMLHttpRequest)  
  22.                 {  
  23.                     return _newCreateXhr;  
  24.                 }  
  25.                 else  
  26.                 {  
  27.                     return _ieCreateXhr;  
  28.                 }  
  29.             }  
  30.   
  31.             return {getInstance: function ()  
  32.             {  
  33.                 if (_instance == null)  
  34.                 {  
  35.                     _instance = _constructor();  
  36.                 }  
  37.                 return _instance;  
  38.   
  39.             }};  
  40.   
  41.         })();  

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <script type="text/javascript">  
  2.   
  3.         var xhrFactoryMethod = ZhangHongYang.xhrFactroy.getInstance();  
  4.         console.log(xhrFactoryMethod());  
  5.   
  6.     </script>  

只有使用时才会去执行_constructor()方法,而不是我们之前的一加载完成就执行。



好了,js的单例模式已经常用的方法介绍完了,以后在书写js代码时,可以尝试使用上述的方法进行书写,而不是大量定义全局function以及变量,请不要在html标签中增加事件处理的代码~


如果存在任何问题,或者有任何问题请留言~

HTML5 CSS3 诱人的实例 :模仿优酷视频截图功能

一般的视频网站对于用户上传的视频,在用户上传完成后,可以对播放的视频进行截图,然后作为视频的展示图。项目中也可以引入这样的功能给用户一种不错的体验,而不是让用户额外上传一张展示图。

效果图:


看起来还是很不错,下面我给大家分析下,极其核心代码很简单:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. _canvas = document.createElement("canvas");  
  2. _ctx = _canvas.getContext("2d");  
  3. _ctx.fillStyle = '#ffffff';  
  4. _ctx.fillRect(0, 0, _videoWidth, _videoWidth);  
  5. _ctx.drawImage(_video, 0, 0, _videoWidth, _videoHeight, 0, 0, _videoWidth, _videoHeight);  
  6. var dataUrl = _canvas.toDataURL("image/png");  
核心代码就这几行,利用了ctx.drawImage时,第一个参数可以为video对象,然后就是通过canvas拿到DataUrl,赋值给Img标签了。关键点就这些。


下面来看整个例子:

HTML:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title></title>  
  5.     <meta charset="utf-8">  
  6.   
  7.     <style type="text/css">  
  8.   
  9.   
  10.         html  
  11.         {  
  12.             overflow: hidden;  
  13.         }  
  14.   
  15.         body  
  16.         {  
  17.             background-color: #999;  
  18.         }  
  19.   
  20.         video  
  21.         {  
  22.             display: block;  
  23.             margin: 60px auto 0;  
  24.         }  
  25.   
  26.         #shotBar  
  27.         {  
  28.             position: absolute;  
  29.             bottom: 5px;  
  30.             height: 120px;  
  31.             width: 98%;  
  32.             background-color: #000;  
  33.             box-shadow: -5px -5px 10px #fff;  
  34.             border-radius: 5px;  
  35.             padding: 2px;  
  36.             overflow: auto;  
  37.         }  
  38.   
  39.         #shotBar img  
  40.         {  
  41.             border: 3px solid #fff;  
  42.             border-radius: 5px;  
  43.             height: 110px;  
  44.             width: 210px;  
  45.             margin-left: 4px;  
  46.         }  
  47.   
  48.   
  49.     </style>  
  50.   
  51.     <script type="text/javascript" src="../../../jquery-1.8.3.js"></script>  
  52.   
  53.     <script type="text/javascript" src="videoshot.js"></script>  
  54.   
  55.     <script type="text/javascript">  
  56.   
  57.         $(function ()  
  58.         {  
  59.             ZhangHongyang.click2shot.init();  
  60.         });  
  61.   
  62.     </script>  
  63.   
  64.   
  65. </head>  
  66. <body>  
  67.   
  68.   
  69. <video src="media/style.mp4" controls id="video">  
  70. </video>  
  71. <div id="shotBar">  
  72. </div>  
  73. </body>  
  74. </html>  

html和css都是相当简单的。

主要看Js的代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 14-6-18 
  5.  * Time: 上午12:24 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8.   
  9. var ZhangHongyang = {};  
  10. ZhangHongyang.click2shot = (function ()  
  11. {  
  12.     var _ID_VIDEO = "video";  
  13.     var _ID_SHOTBAR = "shotBar";  
  14.     var _videoWidth = 0;  
  15.     var _videoHeight = 0;  
  16.     var _canvas = null;  
  17.     var _ctx = null;  
  18.     var _video = null;  
  19.   
  20.     function _init()  
  21.     {  
  22.         _canvas = document.createElement("canvas");  
  23.         _ctx = _canvas.getContext("2d");  
  24.         _video = document.getElementById(_ID_VIDEO);  
  25.   
  26.   
  27.         _video.addEventListener("canplay"function ()  
  28.         {  
  29.             _canvas.width = _videoWidth = _video.videoWidth;  
  30.             _canvas.height = _videoHeight = _video.videoHeight;  
  31.             console.log(_videoWidth + " , " + _videoHeight);  
  32.             _ctx.fillStyle = '#ffffff';  
  33.             _ctx.fillRect(0, 0, _videoWidth, _videoWidth);  
  34.             $("#" + _ID_SHOTBAR).click(_click2shot);  
  35.   
  36.             _video.removeEventListener("canplay", arguments.callee);  
  37.         });  
  38.   
  39.     }  
  40.   
  41.     function _click2shot(event)  
  42.     {  
  43.         _video.pause();  
  44.         _ctx.drawImage(_video, 0, 0, _videoWidth, _videoHeight, 0, 0, _videoWidth, _videoHeight);  
  45.         var dataUrl = _canvas.toDataURL("image/png");  
  46.   
  47.         //创建一个和video相同位置的图片  
  48.         var $imgBig = $("<img/>");  
  49.   
  50.         $imgBig.width(_videoWidth).height(_videoHeight).css({position: "absolute", left: _video.offsetLeft, top: _video.offsetTop, width: _videoWidth + "px", height: _videoWidth + "px"}).attr("src", dataUrl);  
  51.         $("body").append($imgBig);  
  52.   
  53.         //创建缩略图,准备加到shotBar  
  54.         var $img = $("<img>");  
  55.         $img.attr("src", dataUrl);  
  56.         $(this).append($img);  
  57.   
  58.         var offset = _getOffset($img[0]);  
  59.         $img.hide();  
  60.         //添加动画效果  
  61.         $imgBig.animate({left: offset.x + "px", top: offset.y + "px", width: $img.width() + "px", height: $img.height() + "px"}, 200, function ()  
  62.         {  
  63.             $img.attr("src", dataUrl).show();  
  64.             $imgBig.remove();  
  65.             _video.play();  
  66.         });  
  67.   
  68.   
  69.     }  
  70.   
  71.     /** 
  72.      * 获取元素在显示区域的leftOffset和topOffset 
  73.      * @param elem 
  74.      * @returns {{x: (Number|number), y: (Number|number)}} 
  75.      * @private 
  76.      */  
  77.     function _getOffset(elem)  
  78.     {  
  79.         var pos = {x: elem.offsetLeft, y: elem.offsetTop};  
  80.         var offsetParent = elem.offsetParent;  
  81.         while (offsetParent)  
  82.         {  
  83.             pos.x += offsetParent.offsetLeft;  
  84.             pos.y += offsetParent.offsetTop;  
  85.             offsetParent = offsetParent.offsetParent;  
  86.         }  
  87.         return pos;  
  88.     }  
  89.   
  90.   
  91.     return {init: _init}  
  92.   
  93. })();  

需要注意的是,video.canplay事件中获取完属性和一些操作后,一定要removeEventLinstener,否则暂停播放会一直调用此方法。点击事件时,会暂停video,然后在video的位置生成一张图片,使用jquery动画移动到缩略图的位置,然后移除文档,缩略图显示,造成的动画效果。


得到图片之后的上传之类的操作,大家可以自己添加。还有很重要的一点:canvas.toDataURL("image/png");可能需要在服务器中访问才能正常使用,我把写好的页面拖到了tomcat中,大家可以随便启动个什么服务器,不然会报安全问题。


好了,如果这篇文章对你有帮助请顶一个,同时也欢迎大家留言~

 

HTML5 CSS3 诱人的实例 :canvas 模拟实现电子彩票刮刮乐

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/34089553

今天给大家带来一个刮刮乐的小例子~基于HTML5 canvas的,有兴趣的可以改成android版本的,或者其他的~

效果图:


贴一张我中500w的照片,咋办啊,怎么花呢~


好了,下面开始原理:

1、刮奖区域两个Canvas,一个是front , 一个back ,front遮盖住下面的canvas。

2、canvas默认填充了一个矩形,将下面canvas效果图遮盖,然后监听mouse事件,根据mousemove的x,y坐标,进行擦出front canvas上的矩形区域,然后显示出下面的canvas的效果图。

很简单把~嘿嘿~


1、HTML文件内容:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title></title>  
  5.     <meta charset="utf-8">  
  6.   
  7.     <script type="text/javascript" src="../../jquery-1.8.3.js"></script>  
  8.     <script type="text/javascript" src="canvas2d.js"></script>  
  9.   
  10.     <script type="text/javascript" src="GuaGuaLe2.js"></script>  
  11.   
  12.     <script type="text/javascript">  
  13.   
  14.         $(function ()  
  15.         {  
  16.             var guaguale = new GuaGuaLe("front", "back");  
  17.             guaguale.init({msg: "¥5000000.00"});  
  18.         });  
  19.     </script>  
  20.     <style type="text/css">  
  21.   
  22.   
  23.         body  
  24.         {  
  25.             background: url("s_bd.jpg") repeat 0 0;  
  26.         }  
  27.   
  28.         .container  
  29.         {  
  30.             position: relative;  
  31.             width: 400px;  
  32.             height: 160px;  
  33.             margin: 100px auto 0;  
  34.             background: url(s_title.png) no-repeat 0 0;  
  35.             background-size: 100% 100%;  
  36.         }  
  37.   
  38.         #front, #back  
  39.         {  
  40.             position: absolute;  
  41.             width: 200px;  
  42.             left: 50%;  
  43.             top: 100%;  
  44.             margin-left: -130px;  
  45.             height: 80px;  
  46.             border-radius: 5px;  
  47.             border: 1px solid #444;  
  48.         }  
  49.   
  50.     </style>  
  51.   
  52. </head>  
  53. <body>  
  54.   
  55. <div class="container">  
  56.     <canvas id="back" width="200" height="80"></canvas>  
  57.     <canvas id="front" width="200" height="80"></canvas>  
  58. </div>  
  59.   
  60.   
  61. </body>  
  62. </html>  



2、首先我利用了一个以前写的canvas辅助类,留下来今天要用的一些方法:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 13-12-17 
  5.  * Time: 下午9:42 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8.   
  9. function Canvas2D($canvas)  
  10. {  
  11.     var context = $canvas[0].getContext("2d"),  
  12.         width = $canvas[0].width,  
  13.         height = $canvas[0].height,  
  14.         pageOffset = $canvas.offset();  
  15.   
  16.   
  17.     context.font = "24px Verdana, Geneva, sans-serif";  
  18.     context.textBaseline = "top";  
  19.   
  20.   
  21.     /** 
  22.      * 绘制矩形 
  23.      * @param start 
  24.      * @param end 
  25.      * @param isFill 
  26.      */  
  27.     this.drawRect = function (start, end, isFill)  
  28.     {  
  29.         var w = end.x - start.x , h = end.y - start.y;  
  30.         if (isFill)  
  31.         {  
  32.             context.fillRect(start.x, start.y, w, h);  
  33.         }  
  34.         else  
  35.         {  
  36.             context.strokeRect(start.x, start.y, w, h);  
  37.         }  
  38.     };  
  39.   
  40.     /** 
  41.      * 根据书写的文本,得到该文本在canvas上书写的中心位置的左上角坐标 
  42.      * @param text 
  43.      * @returns {{x: number, y: number}} 
  44.      */  
  45.     this.caculateTextCenterPos = function (text)  
  46.     {  
  47.         var metrics = context.measureText(text);  
  48.         console.log(metrics);  
  49. //        context.font = fontSize + "px Verdana, Geneva, sans-serif";  
  50.         var textWidth = metrics.width;  
  51.         var textHeight = parseInt(context.font);  
  52.   
  53.         return {  
  54.             x: width / 2 - textWidth / 2,  
  55.             y: height / 2 - textHeight / 2  
  56.         };  
  57.     }  
  58.     this.width = function ()  
  59.     {  
  60.         return width;  
  61.     }  
  62.     this.height = function ()  
  63.     {  
  64.         return height;  
  65.     }  
  66.     this.resetOffset = function ()  
  67.     {  
  68.         pageOffset = $canvas.offset();  
  69.     }  
  70.     /** 
  71.      * 当屏幕大小发生变化,重新计算offset 
  72.      */  
  73.     $(window).resize(function ()  
  74.     {  
  75.         pageOffset = $canvas.offset();  
  76.     });  
  77.   
  78.     /** 
  79.      * 将页面上的左边转化为canvas中的坐标 
  80.      * @param pageX 
  81.      * @param pageY 
  82.      * @returns {{x: number, y: number}} 
  83.      */  
  84.     this.getCanvasPoint = function (pageX, pageY)  
  85.     {  
  86.         return{  
  87.             x: pageX - pageOffset.left,  
  88.             y: pageY - pageOffset.top  
  89.         }  
  90.     }  
  91.     /** 
  92.      * 清除区域,此用户鼠标擦出刮奖涂层 
  93.      * @param start 
  94.      * @returns {*} 
  95.      */  
  96.     this.clearRect = function (start)  
  97.     {  
  98.         context.clearRect(start.x, start.y, 10, 10);  
  99.         return this;  
  100.     };  
  101.   
  102.     /** 
  103.      *将文本绘制到canvas的中间 
  104.      * @param text 
  105.      * @param fill 
  106.      */  
  107.     this.drawTextInCenter = function (text, fill)  
  108.     {  
  109.         var point = this.caculateTextCenterPos(text);  
  110.         if (fill)  
  111.         {  
  112.             context.fillText(text, point.x, point.y);  
  113.         }  
  114.         else  
  115.         {  
  116.             context.strokeText(text, point.x, point.y);  
  117.         }  
  118.     };  
  119.     /** 
  120.      * 设置画笔宽度 
  121.      * @param newWidth 
  122.      * @returns {*} 
  123.      */  
  124.     this.penWidth = function (newWidth)  
  125.     {  
  126.         if (arguments.length)  
  127.         {  
  128.             context.lineWidth = newWidth;  
  129.             return this;  
  130.         }  
  131.         return context.lineWidth;  
  132.     };  
  133.   
  134.     /** 
  135.      * 设置画笔颜色 
  136.      * @param newColor 
  137.      * @returns {*} 
  138.      */  
  139.     this.penColor = function (newColor)  
  140.     {  
  141.         if (arguments.length)  
  142.         {  
  143.             context.strokeStyle = newColor;  
  144.             context.fillStyle = newColor;  
  145.             return this;  
  146.         }  
  147.   
  148.         return context.strokeStyle;  
  149.     };  
  150.   
  151.     /** 
  152.      * 设置字体大小 
  153.      * @param fontSize 
  154.      * @returns {*} 
  155.      */  
  156.     this.fontSize = function (fontSize)  
  157.     {  
  158.         if (arguments.length)  
  159.         {  
  160.             context.font = fontSize + "px Verdana, Geneva, sans-serif";  
  161.   
  162.             return this;  
  163.         }  
  164.   
  165.         return context.fontSize;  
  166.     }  
  167.   
  168.   
  169. }  

这个类也就对Canvas对象进行了简单的封装,设置参数,绘制图形什么的,比较简单,大家可以完善下这个类~

3、GuaGuaLe.js

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 14-6-24 
  5.  * Time: 上午11:36 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8. function GuaGuaLe(idFront, idBack)  
  9. {  
  10.     this.$eleBack = $("#" + idBack);  
  11.     this.$eleFront = $("#" + idFront);  
  12.     this.frontCanvas = new Canvas2D(this.$eleFront);  
  13.     this.backCanvas = new Canvas2D(this.$eleBack);  
  14.   
  15.     this.isStart = false;  
  16.   
  17. }  
  18.   
  19. GuaGuaLe.prototype = {  
  20.     constructor: GuaGuaLe,  
  21.     /** 
  22.      * 将用户的传入的参数和默认参数做合并 
  23.      * @param desAttr 
  24.      * @returns {{frontFillColor: string, backFillColor: string, backFontColor: string, backFontSize: number, msg: string}} 
  25.      */  
  26.     mergeAttr: function (desAttr)  
  27.     {  
  28.         var defaultAttr = {  
  29.             frontFillColor: "silver",  
  30.             backFillColor: "gold",  
  31.             backFontColor: "red",  
  32.             backFontSize: 24,  
  33.             msg: "谢谢惠顾"  
  34.         };  
  35.         for (var p in  desAttr)  
  36.         {  
  37.             defaultAttr[p] = desAttr[p];  
  38.         }  
  39.   
  40.         return defaultAttr;  
  41.   
  42.     },  
  43.   
  44.   
  45.     init: function (desAttr)  
  46.     {  
  47.   
  48.         var attr = this.mergeAttr(desAttr);  
  49.   
  50.         //初始化canvas  
  51.         this.backCanvas.penColor(attr.backFillColor);  
  52.         this.backCanvas.fontSize(attr.backFontSize);  
  53.         this.backCanvas.drawRect({x: 0, y: 0}, {x: this.backCanvas.width(), y: this.backCanvas.height()}, true);  
  54.         this.backCanvas.penColor(attr.backFontColor);  
  55.         this.backCanvas.drawTextInCenter(attr.msg, true);  
  56.         //初始化canvas  
  57.         this.frontCanvas.penColor(attr.frontFillColor);  
  58.         this.frontCanvas.drawRect({x: 0, y: 0}, {x: this.frontCanvas.width(), y: this.frontCanvas.height()}, true);  
  59.   
  60.         var _this = this;  
  61.         //设置事件  
  62.         this.$eleFront.mousedown(function (event)  
  63.         {  
  64.             _this.mouseDown(event);  
  65.         }).mousemove(function (event)  
  66.             {  
  67.                 _this.mouseMove(event);  
  68.             }).mouseup(function (event)  
  69.             {  
  70.                 _this.mouseUp(event);  
  71.             });  
  72.     },  
  73.     mouseDown: function (event)  
  74.     {  
  75.         this.isStart = true;  
  76.         this.startPoint = this.frontCanvas.getCanvasPoint(event.pageX, event.pageY);  
  77.     },  
  78.     mouseMove: function (event)  
  79.     {  
  80.         if (!this.isStart)return;  
  81.         var p = this.frontCanvas.getCanvasPoint(event.pageX, event.pageY);  
  82.         this.frontCanvas.clearRect(p);  
  83.     },  
  84.     mouseUp: function (event)  
  85.     {  
  86.         this.isStart = false;  
  87.     }  
  88. };  

通过用户传入的两个canvas的id,然后生成一个对象,进行初始化操作,设置事件。当然了也提供用户设置可选的参数,各种颜色,已经刮开后显示的信息等,通过{
            frontFillColor: "silver",
            backFillColor: "gold",
            backFontColor: "red",
            backFontSize: 24,
            msg: "谢谢惠顾"
        };传给init方法进行设置。

好了,然后就基本完工了,测试一下:

基本实现了刮开图层,但是存在一个小问题,就是当用户滑动特别快时,会出现一些断点,当然也可以忽略,不过我们准备提供一下解决方案:


产生原因:由于鼠标移动速度过快,产生的断点;解决方案:将mousemove中两次的鼠标左边,进行拆分成多个断点坐标:



如上图,把两点之间进行连线,根据斜率,然后分成多个小段,分别获得线段上的坐标(有四种可能,有兴趣可以画画图,计算下,代码如下):

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. var k;  
  2.       if (p.x > this.startPoint.x)  
  3.       {  
  4.           k = (p.y - this.startPoint.y) / (p.x - this.startPoint.x);  
  5.           for (var i = this.startPoint.x; i < p.x; i += 5)  
  6.           {  
  7.               this.frontCanvas.clearRect({x: i, y: (this.startPoint.y + (i - this.startPoint.x) * k)});  
  8.           }  
  9.       } else  
  10.       {  
  11.           k = (p.y - this.startPoint.y) / (p.x - this.startPoint.x);  
  12.           for (var i = this.startPoint.x; i > p.x; i -= 5)  
  13.           {  
  14.               this.frontCanvas.clearRect({x: i, y: (this.startPoint.y + ( i - this.startPoint.x  ) * k)});  
  15.           }  
  16.       }  
  17.       this.startPoint = p;  

4、最后贴一下完整的GuaGuaLe.js

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Created with JetBrains WebStorm. 
  3.  * User: zhy 
  4.  * Date: 14-6-24 
  5.  * Time: 上午11:36 
  6.  * To change this template use File | Settings | File Templates. 
  7.  */  
  8. function GuaGuaLe(idFront, idBack)  
  9. {  
  10.     this.$eleBack = $("#" + idBack);  
  11.     this.$eleFront = $("#" + idFront);  
  12.     this.frontCanvas = new Canvas2D(this.$eleFront);  
  13.     this.backCanvas = new Canvas2D(this.$eleBack);  
  14.   
  15.     this.isStart = false;  
  16.   
  17. }  
  18.   
  19. GuaGuaLe.prototype = {  
  20.     constructor: GuaGuaLe,  
  21.     /** 
  22.      * 将用户的传入的参数和默认参数做合并 
  23.      * @param desAttr 
  24.      * @returns {{frontFillColor: string, backFillColor: string, backFontColor: string, backFontSize: number, msg: string}} 
  25.      */  
  26.     mergeAttr: function (desAttr)  
  27.     {  
  28.         var defaultAttr = {  
  29.             frontFillColor: "silver",  
  30.             backFillColor: "gold",  
  31.             backFontColor: "red",  
  32.             backFontSize: 24,  
  33.             msg: "谢谢惠顾"  
  34.         };  
  35.         for (var p in  desAttr)  
  36.         {  
  37.             defaultAttr[p] = desAttr[p];  
  38.         }  
  39.   
  40.         return defaultAttr;  
  41.   
  42.     },  
  43.   
  44.   
  45.     init: function (desAttr)  
  46.     {  
  47.   
  48.         var attr = this.mergeAttr(desAttr);  
  49.   
  50.         //初始化canvas  
  51.         this.backCanvas.penColor(attr.backFillColor);  
  52.         this.backCanvas.fontSize(attr.backFontSize);  
  53.         this.backCanvas.drawRect({x: 0, y: 0}, {x: this.backCanvas.width(), y: this.backCanvas.height()}, true);  
  54.         this.backCanvas.penColor(attr.backFontColor);  
  55.         this.backCanvas.drawTextInCenter(attr.msg, true);  
  56.         //初始化canvas  
  57.         this.frontCanvas.penColor(attr.frontFillColor);  
  58.         this.frontCanvas.drawRect({x: 0, y: 0}, {x: this.frontCanvas.width(), y: this.frontCanvas.height()}, true);  
  59.   
  60.         var _this = this;  
  61.         //设置事件  
  62.         this.$eleFront.mousedown(function (event)  
  63.         {  
  64.             _this.mouseDown(event);  
  65.         }).mousemove(function (event)  
  66.             {  
  67.                 _this.mouseMove(event);  
  68.             }).mouseup(function (event)  
  69.             {  
  70.                 _this.mouseUp(event);  
  71.             });  
  72.     },  
  73.     mouseDown: function (event)  
  74.     {  
  75.         this.isStart = true;  
  76.         this.startPoint = this.frontCanvas.getCanvasPoint(event.pageX, event.pageY);  
  77.     },  
  78.     mouseMove: function (event)  
  79.     {  
  80.         if (!this.isStart)return;  
  81.         var p = this.frontCanvas.getCanvasPoint(event.pageX, event.pageY);  
  82.         this.frontCanvas.clearRect(p);  
  83.     },  
  84.     mouseUp: function (event)  
  85.     {  
  86.         this.isStart = false;  
  87.     }  
  88. };  

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/34089553 

好了,收工吃饭~




HTML5 CSS3 诱人的实例 : 网页加载进度条的实现,下载进度条等


今天给大家带来一个比较炫的进度条,进度条在一耗时操作上给用户一个比较好的体验,不会让用户觉得在盲目等待,对于没有进度条的长时间等待,用户会任务死机了,毫不犹豫的关掉应用;一般用于下载任务,删除大量任务,网页加载等;如果有使用html5为手机布局的,也可以用于手机中~

效果图:

1、html结构:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <div id="loadBar01" class="loadBar">  
  2.        <div>  
  3.             <span class="percent">  
  4.                <i></i>  
  5.             </span>  
  6.        </div>  
  7.        <span class="percentNum">0%</span>  
  8.    </div>  
简单分析下:
div.loadBar代表整个进度条

div.loadBar div 设置了圆角表框 ,div.loadBar div  span 为进度 (动态改变宽度),  div.loadBar div  span i 为进度填充背景色(即width=100%)

HTML的结构,大家可以自己设计,只要合理,都没有问题~

2、CSS:

[css] view plaincopy在CODE上查看代码片派生到我的代码片
  1. body  
  2.        {  
  3.            font-family: Thoma, Microsoft YaHei, 'Lato', Calibri, Arialsans-serif;  
  4.        }  
  5.   
  6.        #content  
  7.        {  
  8.            margin120px auto;  
  9.            width80%;  
  10.        }  
  11.   
  12.        .loadBar  
  13.        {  
  14.            width600px;  
  15.            height30px;  
  16.            border3px solid #212121;  
  17.            border-radius: 20px;  
  18.            positionrelative;  
  19.        }  
  20.   
  21.        .loadBar div  
  22.        {  
  23.            width100%;  
  24.            height100%;  
  25.            positionabsolute;  
  26.            top: 0;  
  27.            left: 0;  
  28.        }  
  29.   
  30.        .loadBar div span, .loadBar div i  
  31.        {  
  32.            box-shadow: inset 0 -2px 6px rgba(000, .4);  
  33.            width0%;  
  34.            displayblock;  
  35.            height100%;  
  36.            positionabsolute;  
  37.            top: 0;  
  38.            left: 0;  
  39.            border-radius: 20px;  
  40.        }  
  41.   
  42.        .loadBar div i  
  43.        {  
  44.            width100%;  
  45.            -webkit-animation: move .8s linear infinite;  
  46.            background: -webkit-linear-gradient(left top#7ed047 0%, #7ed047 25%, #4ea018 25%, #4ea018 50%, #7ed047 50%, #7ed047 75%, #4ea018 75%, #4ea018 100%);  
  47.            background-size40px 40px;  
  48.        }  
  49.   
  50.        .loadBar .percentNum  
  51.        {  
  52.            positionabsolute;  
  53.            top: 100%;  
  54.            right: 10%;  
  55.            padding1px 15px;  
  56.            border-bottom-left-radius: 16px;  
  57.            border-bottom-right-radius: 16px;  
  58.            border1px solid #222;  
  59.            background-color#222;  
  60.            color#fff;  
  61.   
  62.        }  
  63.   
  64.        @-webkit-keyframes move  
  65.        {  
  66.            0%  
  67.            {  
  68.                background-position0 0;  
  69.            }  
  70.            100%  
  71.            {  
  72.                background-position40px 0;  
  73.            }  
  74.        }  

此时效果为:


整体布局就是利用position relative和absolute~

比较难的地方就是,渐变条的实现:

我们采用

a、从左上到右下的渐变

b、颜色分别为:0-25% 为#7ed047 , 25%-50% 为#4ea018 , 50%-75%为#7ed047 , 75%-100%为#4ea018

c、背景的大小为40px 40px 这个设置超过高度就行, 越大,条文宽度越宽 

分析图:


设置的原理就是上图了,同时可以背景宽度设置越大,条文宽度越大;

3、设置Js,创建LoadBar对象

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. function LoadingBar(id)  
  2.        {  
  3.            this.loadbar = $("#" + id);  
  4.            this.percentEle = $(".percent"this.loadbar);  
  5.            this.percentNumEle = $(".percentNum"this.loadbar);  
  6.            this.max = 100;  
  7.            this.currentProgress = 0;  
  8.        }  
  9.        LoadingBar.prototype = {  
  10.            constructor: LoadingBar,  
  11.            setMax: function (maxVal)  
  12.            {  
  13.                this.max = maxVal;  
  14.            },  
  15.            setProgress: function (val)  
  16.            {  
  17.                if (val >= this.max)  
  18.                {  
  19.                    val = this.max;  
  20.                }  
  21.                this.currentProgress = parseInt((val / this.max) * 100) + "%";  
  22.                this.percentEle.width(this.currentProgress);  
  23.                this.percentNumEle.text(this.currentProgress);  
  24.   
  25.   
  26.            }  
  27.        };  

我们创建了一个LoadBar对象,同时公开了两个方法,一个设置最大进度,一个设置当前进度;比如下载文件最大进度为文件大小,当前进度为已下载文件大小。

4、测试

最后我们测试下我们的代码:

[javascript] view plaincopy在CODE上查看代码片派生到我的代码片
  1. $(function ()  
  2.      {  
  3.   
  4.          var loadbar = new LoadingBar("loadBar01");  
  5.          var max = 1000;  
  6.          loadbar.setMax(max);  
  7.          var i = 0;  
  8.          var time = setInterval(function ()  
  9.          {  
  10.              loadbar.setProgress(i);  
  11.              if (i == max)  
  12.              {  
  13.                  clearInterval(time);  
  14.                  return;  
  15.              }  
  16.              i += 10;  
  17.          }, 40);  
  18.      });  

ps:对于js对象的设计,尽可能的考虑实用性~

最后完工~哈~ 吃饭吃饭~ 













0 0
原创粉丝点击