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"
相關文章
相關標籤/搜索