一、開篇
最近在網上看到了一款canvas實現網頁塗鴉效果的作品,感覺這個效果比較奇特而且在以前沒有學習canvas這樣的功能是不可思議的,所以本人秉着程序員的那一份執着,花了兩三個小時的時間來研究了一下canvas塗鴉作品的代碼,發現里面代碼比較精辟,但是美中不足的是有些代碼的結構會比較的混亂,讓人感覺層次上面有點不太分明。所以本人就打算對這個代碼結構進行重構使其更具有可讀性。但是理想是豐滿的現實是骨感的,經過這一次代碼的分析和實踐下來,對我也是打擊蠻大的,以前從來都是認為前端只要能夠熟悉調試工具就行了,但是這一次調試工具居然“失靈”了,具體的失靈原因最終也沒有找到,失靈表現在:在調試上面去監控元素會發現得到的值是正確的,但是最終運行的結果卻是錯誤。打擊雖大,但是我也是挺高興的,至少我現在懂得了學會了一些代碼重構的方法和理解清楚了什么是this的指向之類的問題
二、代碼結構的編寫
由於我為了鞏固之前在深入學習JavaScript(二)中提到的繼承,所以采用的方法是將執行的方法都書寫在new方法(對應下面的canvas)的父類中,然后在window.onload事件中實例化canvas類,canvas類中是將傳入的參數傳遞給canvas的父類來的
簡化后的JavaScript結構代碼如下:
window.onload=function(){ const A=1; var B=2; new canvas(A,B); } function canvas(a,b){
var c=3;
console.log(this.c): this.init.apply(this,arguments); } canvas.prototype={ init:function(A,B){ console.log(A+","+B); } }
這里面我們需要注意的是:this.init.apply(this,arguments);這句話主要是用來this指的是當前調用的對象,也就是canvas對象(通過new canvas(A,B)來調用),但是你有沒有注意到將變量c打印出來的結果是undefined,但是我們說this指的是canvas對象,這是為什么呢?其實我們在深入學習JavaScript(一)中就已經介紹過了,只不過沒有在實際的項目中進行詳解,因為通過var創建的變量c,是在window對象中聲明的,不是在canvas對象中,所以我們只需要將var c=3改為this.c=3這樣就可以正常運行了。還有這個時候this所指代的canvas對象包含有它的父類。總的一句話:調用這個方法或者是類的時候調用的對象是什么,那么這里面的this指代的就是什么。如果在調用對象不明確的時候,我們可以在調用對象的上級查找,因為如果是當前的對象沒有發生變化的時候是會繼承上級的this對象到下級的,這樣會導致當前的對象比較難發現,示例:
window.onload=function(){ const A=1; var B=2; console.log(this); new canvas(A,B); } function canvas(a,b){ this.c=3; console.log(this.c); this.init.apply(this,arguments); } canvas.prototype={ init:function(A,B){ console.log(A+","+B); this.test(); }, test:function(){ alert('this is test'); } }
分析:在this.test()這個執行語句中,我們單從這個語句很難分析出this指代的是什么,所以我們需要向上查找,在canvas對象中的apply方法調用了init這個函數,由於這個canvas對象是被new canvas(A,B)初始化的,所以canvas對象中的this指代的是canvas對象,即canvas對象中的方法和變量。因為this對象沒有改變,所以this會一級一級的向下繼承,最終this.test()中的this就是指代canvas對象
PS:apply的用法跟call的用法相似,但是只要的用途是用來將當前傳入的參數傳遞給父類,這里我們以apply為例來進行講解
在上面的例子中我們對apply這個方法傳入的參數是:A=1;B=2,這一步相信地球人都可以看得出來。所以關鍵還是理解arguments這個代表什么意思,arguments這個會被編譯器解析為不定長的數組(其實在JavaScript中的數組都是不定長的,這個有別於其他的高級語言,例如:C#、java),然后會分別將A=1,B=2分別存放在數組的0號位上和1號位上,所以arguments=[1,2],call的作用是一樣一樣的,但是不是通過arguments這個參數來代表要傳入的參數,而是直接將參數寫在里面,例如:call(this,A,B)
三、其他一些需要注意的細節和知識點回顧
CSS 精靈技術
CSS精靈技術這個對於比較年老的程序員來說應該都聽說過吧,但是新一代的程序員中使用的比較少
個人認為主要的原因是:
1、制作一張精靈圖花費的時間比較久(但是node.js的出現已經有了生成圖片的工具)
2、精靈圖不是矢量圖,所以不能夠適應現在的響應式布局
3、精靈要求在CSS定位上面的操作准確,這個會增大程序員的時間成本
但是CSS精靈技術也是有自己的有點的
1、精靈圖其實就是將圖標集成為一張圖片,所以在瀏覽器向服務器發送請求的時候,服務器也就只需要返回一次數據就夠了(當然這里沒有包括JavaScript、HTML、CSS文件和其他文件),這個也是最重要的。
PS:這里面的CSS精靈技術權當溫故知新,如果沒興趣的同學可以跳過。本人也認為現在的SVG圖標已經基本上代替了以前的這種CSS精靈技術,而且更加方便
好的,我們這就來開始精靈技術的案例
我們先准備一張雪碧圖
然后HTML代碼是這樣的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CSS精靈技術DEMO</title> <style> #showArea{ } .btn{ width:200px; height:65px; background:url(DEMO.png); background-position:0px -65px; } .btn:hover{ background-position:0px -130px; } </style> </head> <body> <div id="showArea"> <div class="btn"></div> </div> </body> </html>
運行后的結果是:
幾個獲取坐標的API之間的辨析
這里我們以寬相關的來做辨析,獲取長的基本上一模一樣
offsetX,clientX,offsetLeft,window.screen.width
offsetX:所在的DOM對象中的坐標,以DOM對象的左上角坐標為原點
clientX:獲取的是相對於WINDOW對象的寬度
如果是DOM對象與左邊距為0的時候,那么clientX=offsetX
但是如果是存在margin-left這個值得時候,那么clientX=offsetX+offsetLeft
相信說到這里大家都猜到offsetLeft指的是什么吧,沒錯offetLeft指的是DOM對象相對於WINDOW的偏移量
window.screen.width:這個具體指的是屏幕的分辨率寬度,一般在移動設備上使用
四、相關的源碼
這里面提供了一個制作失敗的代碼供大家引以為鑒,里面的代碼中有很多功能都沒有實現,主要的問題是在畫布中畫筆和線段不能同步,這個也是導致失敗的原因,希望各位大神看一看怎樣修改,知道的麻煩再留言中告訴我一下,在此不勝感激,以上就是在這個項目中的體會所得。下載地址