JavaScript面向对象编程实战

2020年08月18日 阅读数:74
这篇文章主要向大家介绍JavaScript面向对象编程实战,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

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

css

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

好了,下面看一个很是简单的例子:html5

[javascript]  view plain copy 在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,上面的代码和它们有几毛钱的关系。好了,下面我先按要求把图画出来,你们参考下:


解析下:java

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

二、全部构造器/函数的__proto__都指向Function的prototypeandroid

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

[javascript]  view plain copy 在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 plain copy 在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 plain copy 在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  


有此可见ajax

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

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


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

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属性。

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

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

看下面的例子:

[javascript]  view plain copy 在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代码,最近恰好温故温故。

一、Javascript没有代码块做用域的概念,局部做用域是针对函数来讲的。


二、若是不使用var声明的变量,默认为全局变量


三、Js中的做用域链

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

做用域链的图:


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


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

下面是做用域链的图:


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

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

四、闭包

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

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


相信上面的代码确定你们都写过,本意是点击每一个li,打印出它们的索引,但是事实上打印出的都是elements.length。这是为何呢?


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

下面看解决方案:


在onclick函数的外层,包了一层当即执行的函数,因此此时的n指向的 n 是当即执行的,全部都是1~elements.length 。 

Javascript 进阶 封装

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

js中到处是对象,面向对象的第一步固然就是封装了,因为Js中没有类的概念,因此封装起来也比较麻烦,下面介绍两种js的封装。

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

  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中,并不是存在对象中,整体来讲仍是个不错的选择。若是你以为,这不行,必须严格实现封装,那么看第二种方式。

二、严格实现封装

  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访问成员变量了,可是存在一个问题,全部的方法都存在对象中,增长了内存的开销。

三、以闭包的方式封装

  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

一、基于类的继承
下面看下面的代码:
[javascript]  view plain copy 在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 plain copy 在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 plain copy 在CODE上查看代码片 派生到个人代码片
  1. <script type="text/javascript">  
  2.        /** 
  3.         * 存在问题 
  4.         * 一、没法在Student的构造方法中传递参数用于父类的构造方法 
  5.         * 二、对于引用类型变量,形成数据不一致 
  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 plain copy 在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 plain copy 在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 plain copy 在CODE上查看代码片 派生到个人代码片
  1. 0001 , 张三 , soccer   
  2. 0002 , 李四 , cangjin,basketball   

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

二、基于原型链的继承

[javascript]  view plain copy 在CODE上查看代码片 派生到个人代码片
  1. <script type="text/javascript">  
  2.   
  3.     /** 
  4.      * 基于原型链的集成中都是对象 
  5.      * 存在问题: 
  6.      * 一、对于引用类型变量,形成数据不一致 
  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 plain copy 在CODE上查看代码片 派生到个人代码片
  1. zhangsan , 12 , Java   
  2. lisi , 13 , Java,Javascript   

能够看出一样存在引用属性不一致的问题,而且整个操做所有基于对象,给人的感受不是很好,下面经过图解解释下原理:


对象间经过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,造成一个链,因此叫作原型链。


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



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

 

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

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

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



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


好了,很少说,js的训练全靠敲,因此若是以为面向对象不是很扎实,能够照着敲一个,若是以为很扎实了,提供了效果图,能够本身写试试。

一、第一个效果图代码:

[javascript]  view plain copy 在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 plain copy 在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的工具使用。


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

[javascript]  view plain copy 在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 plain copy 在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 plain copy 在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的单例模式实现以及用法。

一、单例模式的写法

单例模式写法至关简单:

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

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

二、单例用法一:建立命名空间

在开发中一个页面通常会引入多个Js文件,甚至这多个文件多人写的,你们均可能在全局定义init这个方法,均可能在全局声明name这是属性。这样的话就形成的命名的冲突,发生一些意想不到的问题。因此咱们须要引入命名空间:

咱们可让每一个程序猿写的Js在他本身的命名空间下:

[java]  view plain copy 在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。

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

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

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

html:

[html]  view plain copy 在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 plain copy 在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代码总体上结构清晰;学习使用面向对象的方式处理问题。



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

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

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

[javascript]  view plain copy 在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 plain copy 在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.        })();  

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

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

在web项目中,不少状况会使用到Textarea。

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

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

html:

[javascript]  view plain copy 在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 plain copy 在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 plain copy 在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中供编辑;若是各位项目中没有考虑到这类问题,首先你能够测试下问题,而后可使用上面的代码解决这类问题。

六、单例写法提升多分支代码效率

相信你们都了解过ajax,对象ajax确定离不开XMLHttpRequest,并且不一样版本、类型的浏览器建立方式不一致。通常咱们可能会这么写建立XMLHttpRequest的方法:

[javascript]  view plain copy 在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 plain copy 在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对象。

七、单例引入懒加载功能

上述的js的文件基本在引入页面后,浏览器加载就会进行大量操做占用内存,有时候咱们但愿等到咱们去使用时再去执行一些操做,若是从未使用就省去没必要要的内存消耗,咱们能够进行以下改写代码:

[javascript]  view plain copy 在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 plain copy 在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 plain copy 在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 plain copy 在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 plain copy 在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的照片,咋办啊,怎么花呢~


好了,下面开始原理:

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

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

很简单把~嘿嘿~


一、HTML文件内容:

[html]  view plain copy 在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"