目的:檔案命名時,限制某些字元無法輸入!
限制字元: \ / | ? :
在此種情況下,使用 keypress 事件較為合適
keydown event 會判斷是鍵盤上哪個鍵被按下,
而 keypress event 則會判斷是哪個字元被輸入
舉例來說,輸入小寫字元 "a",
keypress 事件會回傳 97
keydown 事件回傳 65
輸入大寫字元 "A",
keypress 事件回傳 65
keydown 事件回傳 65
由上例可知, keypress 可以準確分辨大寫 "A" 與小寫 "a",
而 keydwon 則因為回傳皆為 65,無法辨識輸入字元為大寫 "A" 或是 小寫 "a"
但 keydown event 能夠偵測某些特殊按鍵,像是 Shift 或是 方向鍵
在本例中,因為希望限制 : 輸入,而 ; 則可以正常輸入
使用 keydown event,則 event.which 值皆為 186
使用 keypress event, ; reported as 59, : reported as 58
所以 keypress event 會較符合此次限制檔案命名需求!
2013年12月26日 星期四
2013年12月2日 星期一
【jQuery】Trigger keyup event
需求:刪除檔案可以點擊"刪除"圖示或是按下鍵盤上"DEL"按鍵
實作:因為兩個方式都是實作刪除檔案,所以可以先寫好其中一個 function,
另一個就直接觸發該 function 即可。
想法:先實作出使用"DEL"鍵刪除;點擊 Icon 則模擬鍵盤事件即可。
另外要注意的是,一般 html tag (ex:div) 需要加上 tabindex 屬性才可以觸發鍵盤事件
而 input tag 則不需要額外加上 tabindex 屬性
實作:因為兩個方式都是實作刪除檔案,所以可以先寫好其中一個 function,
另一個就直接觸發該 function 即可。
想法:先實作出使用"DEL"鍵刪除;點擊 Icon 則模擬鍵盤事件即可。
$('item').keyup(function(event) { if (event.which == 46) { // to do delete file } }); $('.icon').click({ var e = $.Event('keyup'); e.which = 46; // Delete $('item').trigger(e); });
另外要注意的是,一般 html tag (ex:div) 需要加上 tabindex 屬性才可以觸發鍵盤事件
而 input tag 則不需要額外加上 tabindex 屬性
2013年11月29日 星期五
【Javascript】XMLHttpRequest 解決 Cross Domain 檔案下載
需求為 Frontend.js 與 實際檔案放置在不同主機上,
所以需要解決 Cross Domain 資料存取的限制。
解決辦法為採用 XMLHttpRequest 物件來突破跨區存取限制。
直接看 Code
downloadFile 這個函式接收一個參數 _fileUrl 指出檔案路徑
var xhr = new XMLHttpRequest() 建立一個 xhr 物件
withCredentials這個屬性預設為false,
因為 XMLHTTPRequest2 物件才允許CORS(Cross-Origin Resource Sharing),
所以檢查是否有支援withCredentials屬性,
該屬性指示是否使用如cookie或授權標頭檔等憑證進行跨站存取控制(cross-site Access-Control)請求。
而IE 8與IE 9只能使用 XDomainRequest 物件處理 CORS 請求(IE8,9不支援XHR2)
responseType 屬性指定回應狀態,
可以為 blob, json, text 等等,
為了方便後續創造連結,所以指定回應狀態為"blob"
onreadystatechange 這個函式會在 readyState 屬性改變時被呼叫
而 readyState 屬性值為 4 時,表示作業完成。
此時便可以創造一個元素 a,並且呼叫 createObjectURL 方法賦予 href 屬性值,
a.download可以為下載檔案命名,最後呼叫 click 方法完成檔案下載。
還有一件事情須處理,存放檔案的主機要設定允許跨領域存取的權限
後端採用 Node.js 與 Express framework 進行開發
簡單講要幫 response 設定允許跨領域存取的 Header,
'Access-Control-Allow-Origin' 設定允許的請求來源
'Access-Control-Allow-Methods'設定允許的方法,如 GET, POST 等
如果前端 xhr.setRequestHeader 有自行定義 Header 的話
那 Server 這邊也要多加 'Access-Control-Allow-Headers' 權限
就允許帶有 header 為 'X-Requested-With' 的請求。
但要注意的是,因為安全性的關係,XDomainRequest不支援客製化 Header
也限制 Method only GET or POST,Protocol only HTTP or HTTPS
還好IE 10開始支援 XMLHTTPRequest2
所以需要解決 Cross Domain 資料存取的限制。
解決辦法為採用 XMLHttpRequest 物件來突破跨區存取限制。
直接看 Code
downloadFile = function( _fileUrl ) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { xhr.open('GET', _fileUrl, true); } else if (typeof XDomainRequest != "undefined") { xhr = new XDomainRequest(); xhr.open('GET', _fileUrl ); } xhr.responseType = "blob"; xhr.onreadystatechange = function () { if (xhr.readyState == 4) { var a = document.createElement('a'); a.href = window.URL.createObjectURL(xhr.response); a.download = fileName; a.click(); } }; xhr.send(); }
downloadFile 這個函式接收一個參數 _fileUrl 指出檔案路徑
var xhr = new XMLHttpRequest() 建立一個 xhr 物件
withCredentials這個屬性預設為false,
因為 XMLHTTPRequest2 物件才允許CORS(Cross-Origin Resource Sharing),
所以檢查是否有支援withCredentials屬性,
該屬性指示是否使用如cookie或授權標頭檔等憑證進行跨站存取控制(cross-site Access-Control)請求。
而IE 8與IE 9只能使用 XDomainRequest 物件處理 CORS 請求(IE8,9不支援XHR2)
responseType 屬性指定回應狀態,
可以為 blob, json, text 等等,
為了方便後續創造連結,所以指定回應狀態為"blob"
onreadystatechange 這個函式會在 readyState 屬性改變時被呼叫
而 readyState 屬性值為 4 時,表示作業完成。
此時便可以創造一個元素 a,並且呼叫 createObjectURL 方法賦予 href 屬性值,
a.download可以為下載檔案命名,最後呼叫 click 方法完成檔案下載。
還有一件事情須處理,存放檔案的主機要設定允許跨領域存取的權限
後端採用 Node.js 與 Express framework 進行開發
app.configure(function(){ app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', "*"); res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Methods', "GET"); next(); }); });
簡單講要幫 response 設定允許跨領域存取的 Header,
'Access-Control-Allow-Origin' 設定允許的請求來源
'Access-Control-Allow-Methods'設定允許的方法,如 GET, POST 等
如果前端 xhr.setRequestHeader 有自行定義 Header 的話
那 Server 這邊也要多加 'Access-Control-Allow-Headers' 權限
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
就允許帶有 header 為 'X-Requested-With' 的請求。
但要注意的是,因為安全性的關係,XDomainRequest不支援客製化 Header
也限制 Method only GET or POST,Protocol only HTTP or HTTPS
還好IE 10開始支援 XMLHTTPRequest2
2013年11月20日 星期三
【jQuery】hide() 與 fadeOut()
jQuery 的兩個動畫函式 hide() 與 fadeOut() 都具有隱藏效果。
需求是當游標滑入指定區域時,浮現該按鈕,點擊按鈕後可使按鈕180度旋轉。
實現旋轉方式是設定 CSS 的 transform 值, rotate( '旋轉度數' deg )。
若使用 hide() 與 show() 來實作隱藏與浮現效果,
元素隱藏之前的旋轉度數會被保留。
但使用 fadeOut() 與 fadeIn() 來實作的話,
旋轉度數的 CSS 效果會消失。
探究其原因,在於 fadeOut 與 fadeIn 會重寫 DOM element 的 style,
導致原本 style 內的 transform 值消失,因此無法保留旋轉度數。
順便紀錄一下觀察到的 hide() 與 fadeOut() 差異,
相同之處:
相異之處:
需求是當游標滑入指定區域時,浮現該按鈕,點擊按鈕後可使按鈕180度旋轉。
實現旋轉方式是設定 CSS 的 transform 值, rotate( '旋轉度數' deg )。
若使用 hide() 與 show() 來實作隱藏與浮現效果,
元素隱藏之前的旋轉度數會被保留。
但使用 fadeOut() 與 fadeIn() 來實作的話,
旋轉度數的 CSS 效果會消失。
探究其原因,在於 fadeOut 與 fadeIn 會重寫 DOM element 的 style,
導致原本 style 內的 transform 值消失,因此無法保留旋轉度數。
順便紀錄一下觀察到的 hide() 與 fadeOut() 差異,
相同之處:
- display值,設為none
- opacity值,變更為0
相異之處:
- hide() 會將 width 與 height 的值也變更為0,fadeOut() 不改變
- hide() 會保留 style 內的 transform 值
2013年11月12日 星期二
【Node.js】Create Http Server
自己以前寫網站習慣,前端使用JavaScript(or jQuery),後端使用PHP,使用Apache建立Server。
而Node.js則打破此框架,簡單講就是,伺服器端的JavaScript!
為了實現此概念,Node.js借助Google V8引擎在後端運行JavaScript。
想從建立一個基礎Http Server入門,範例code包含三個觀念,使用模組、函數傳遞以及回呼(callback)。
接下來寫一個onRequest函數處理http的請求,這邊我們可以看到http使用createServer方法時,onRequest這個函數被當成是參數來傳遞,此即所謂的函數傳遞。
而Server監聽8888 port同時等待HTTP的請求,當有請求發生時,執行onRequest函式,此即所謂callback。
callback:給甲方法傳遞乙函式,等到對應事件發生時,才執行乙函式。
以上述code來看的話→
甲方法 ─ createServer
乙函式 ─ onRequest
對應事件 ─ HTTP的請求
補充一下,乙函式也很常使用匿名函式。
最後一行code會在命令行上輸出"Server has started.",幫助我們測試程式流程與了解事件的觸發順序,此程式流程為非同步流程,因為http.createServer後,程式會繼續執行,等到有http請求才去執行onRequest函式。
當我們執行腳本後
當我們在瀏覽器輸入localhost:8888後
最後回到命令行會看到
當我們使用瀏覽器讀取網頁時,我們的伺服器有可能會輸出兩次"Request received."。原因為何?我們可以修改code增加解析路徑的功能。
修改code如下
使用Node.js內建url模組,並呼叫其parse方法幫我們解析request.url,
即分析HTTP的請求路徑為何。
腳本編譯完成後,我們一樣開啟browser輸入localhost:8888
然後回到命令列的地方觀看log訊息
觀看log訊息可以知道請求路徑。由此得知,當我們在存取http://localhost:8888的當下, 伺服器也嘗試存取 http://localhost:8888/favicon.ico 。 因此我們上一段code,log訊息才會出現兩次"Request received."。
而Node.js則打破此框架,簡單講就是,伺服器端的JavaScript!
為了實現此概念,Node.js借助Google V8引擎在後端運行JavaScript。
想從建立一個基礎Http Server入門,範例code包含三個觀念,使用模組、函數傳遞以及回呼(callback)。
var http = require("http"); function onRequest(request, response) { console.log("Request received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started.");第一行code很簡單,呼叫Node.js內建http模組並存入http變數。
接下來寫一個onRequest函數處理http的請求,這邊我們可以看到http使用createServer方法時,onRequest這個函數被當成是參數來傳遞,此即所謂的函數傳遞。
而Server監聽8888 port同時等待HTTP的請求,當有請求發生時,執行onRequest函式,此即所謂callback。
callback:給甲方法傳遞乙函式,等到對應事件發生時,才執行乙函式。
以上述code來看的話→
甲方法 ─ createServer
乙函式 ─ onRequest
對應事件 ─ HTTP的請求
補充一下,乙函式也很常使用匿名函式。
最後一行code會在命令行上輸出"Server has started.",幫助我們測試程式流程與了解事件的觸發順序,此程式流程為非同步流程,因為http.createServer後,程式會繼續執行,等到有http請求才去執行onRequest函式。
當我們執行腳本後
當我們在瀏覽器輸入localhost:8888後
當我們使用瀏覽器讀取網頁時,我們的伺服器有可能會輸出兩次"Request received."。原因為何?我們可以修改code增加解析路徑的功能。
修改code如下
var http = require("http"), url = require("url"); function start() { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received."); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello Node.js"); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started."); } exports.start = start;
使用Node.js內建url模組,並呼叫其parse方法幫我們解析request.url,
即分析HTTP的請求路徑為何。
腳本編譯完成後,我們一樣開啟browser輸入localhost:8888
然後回到命令列的地方觀看log訊息
觀看log訊息可以知道請求路徑。由此得知,當我們在存取http://localhost:8888的當下, 伺服器也嘗試存取 http://localhost:8888/favicon.ico 。 因此我們上一段code,log訊息才會出現兩次"Request received."。
2013年11月5日 星期二
【jQuery】將桌面檔案拖曳後上傳
想要將桌面的檔案使用拖曳的方式
拉到指定的區域
就可以啟動檔案上傳的功能
作法為
先來看第一步的code
接下來改寫drop事件
拉到指定的區域
就可以啟動檔案上傳的功能
作法為
- 改寫dragover與dragenter兩個事件,取消這兩個事件的預設效果(主要為over事件,先取消over事件的效果,否則會無法觸發drop事件)
- 將檔案上傳功能寫進drop事件即可完成此項功能
先來看第一步的code
$("div.content").on( 'dragover', function(event) { event.preventDefault(); event.stopPropagation(); } ); $("div.content").on( 'dragenter', function(event) { event.preventDefault(); event.stopPropagation(); } );
接下來改寫drop事件
$("div.content").on( 'drop', function(event){ if(event.originalEvent.dataTransfer){ if(event.originalEvent.dataTransfer.files.length) { event.preventDefault(); event.stopPropagation(); /* Write Upload Function Here */ fileUpload(); } } } );
2013年9月27日 星期五
【Javascript】basic callback
最近上班學習使用node.js這個framework開發Web Application
假設寫了兩個事件,一個是煮水餃事件,另一個是吃水餃事件。
在現實當中,水餃煮熟了才能開始吃,而煮水餃這件事情需要一些時間。
因此在程式邏輯上
會希望吃水餃這個事件等煮水餃事件完成以後才發生
先看一下不使用 callback 的情形
node.js使用 V8 Javascript Engine
Javascript是一個很自由的語言
可以是 Object Oriented 形式或是 functional 形式
若以事件驅動的概念來寫 Javascript
我覺得callback是最基本的觀念與核心
假設寫了兩個事件,一個是煮水餃事件,另一個是吃水餃事件。
在現實當中,水餃煮熟了才能開始吃,而煮水餃這件事情需要一些時間。
因此在程式邏輯上
會希望吃水餃這個事件等煮水餃事件完成以後才發生
先看一下不使用 callback 的情形
function do_a(){ console.log("'do_a':開始煮水餃"); setTimeout( function(){ console.log("'do_a':水餃煮熟了"); }, 1000 ); } function do_b(){ console.log("'do_b':吃水餃"); } do_a(); do_b();
會發現雖然do_a()在do_b()前面執行
但因為do_a()執行需要一段時間
所以就會發生水餃還沒煮熟就開始吃了 XD
再來看看使用 callback 的解決辦法
但因為do_a()執行需要一段時間
所以就會發生水餃還沒煮熟就開始吃了 XD
再來看看使用 callback 的解決辦法
function do_a( callback ){ console.log("'do_a':開始煮水餃"); setTimeout( function(){ console.log("'do_a':水餃煮熟了"); callback && callback(); }, 1000 ); } function do_b(){ console.log("'do_b':吃水餃"); } do_a( function(){ do_b(); } );
使用 callback 寫法的話
就可以確保do_b()在do_a()完成後才被執行
這是使用 callback 最基本的寫法
但 callback 實際上在使用都會帶參數
了解 callback 後,才有辦法學習 node.js 的 events
就可以確保do_b()在do_a()完成後才被執行
這是使用 callback 最基本的寫法
但 callback 實際上在使用都會帶參數
了解 callback 後,才有辦法學習 node.js 的 events
2013年1月1日 星期二
【jQuery UI】使用drap與drop實作sortable
最近在研究jQuert UI,功能很強大且程式碼很簡潔
研究的重點在於利用拖曳的功能作出圖片的排序
使用draggable來使DOM物件能夠被拖曳
使用droppable來讓DOM物件作為容器
HTML當中以block為容器而img為拖曳物件
先來看一下HTML有哪些目標容器與拖曳物件
第一個要注意的地方在於:如何得知drag物件是從哪個block拖曳到另一個block
我是採用drop的事件out與drop來判斷
但要特別注意out event如果拖曳有經過別的容器也會觸發
所以增加一個變數flag來判斷第一次out event的source block
第二個要注意的地方在於:要特別注意事件被觸發的順序
若事件為draggable start與stop以及droppable out與drop
根據我的理解,觸發順序為start→out→drop→stop
另外特別注意droppable事件over與out,我發現在預設的情況下
有可能只觸發over事件,而尚未觸發out事件
因為沒注意到此情況,導致某些情況下拖曳效果會失敗,產生嚴重瑕疵,不可不慎
第三個要注意的地方在於:因為我是用append來使拖曳物件移動到目標容器
但這樣產生的問題是,會被判斷成拖曳失敗而發生revert動畫
後來發現原因是append使拖曳物件到達目標容器後位移效果並沒有消失
可以用css( 'left', '0' )來取消位移
這樣就可以防止拖曳失敗而產生revert動畫
以上三點我覺得最為重要!
下面提幾個小細節的地方:
$(".line")用來顯示定位線,而且要判斷drag物件的out與drop block是左移還右移
為了維持定位線跑的感覺,當觸發over event處理定位線位置
$(".line").addClass('line_clear');先清除定位線再重新繪製
例如:block4→block1,那輔助線就要在block左邊;
反之,則要在block右邊
若要使拖曳物件永遠在top
我的作法是觸發start事件時將拖曳物件的zIndex升高
stop事件則將拖曳物件的zIndex歸零
研究的重點在於利用拖曳的功能作出圖片的排序
使用draggable來使DOM物件能夠被拖曳
使用droppable來讓DOM物件作為容器
HTML當中以block為容器而img為拖曳物件
先來看一下HTML有哪些目標容器與拖曳物件
第一個要注意的地方在於:如何得知drag物件是從哪個block拖曳到另一個block
我是採用drop的事件out與drop來判斷
但要特別注意out event如果拖曳有經過別的容器也會觸發
所以增加一個變數flag來判斷第一次out event的source block
第二個要注意的地方在於:要特別注意事件被觸發的順序
若事件為draggable start與stop以及droppable out與drop
根據我的理解,觸發順序為start→out→drop→stop
另外特別注意droppable事件over與out,我發現在預設的情況下
有可能只觸發over事件,而尚未觸發out事件
因為沒注意到此情況,導致某些情況下拖曳效果會失敗,產生嚴重瑕疵,不可不慎
第三個要注意的地方在於:因為我是用append來使拖曳物件移動到目標容器
但這樣產生的問題是,會被判斷成拖曳失敗而發生revert動畫
後來發現原因是append使拖曳物件到達目標容器後位移效果並沒有消失
可以用css( 'left', '0' )來取消位移
這樣就可以防止拖曳失敗而產生revert動畫
以上三點我覺得最為重要!
下面提幾個小細節的地方:
$(".line")用來顯示定位線,而且要判斷drag物件的out與drop block是左移還右移
為了維持定位線跑的感覺,當觸發over event處理定位線位置
$(".line").addClass('line_clear');先清除定位線再重新繪製
例如:block4→block1,那輔助線就要在block左邊;
反之,則要在block右邊
若要使拖曳物件永遠在top
我的作法是觸發start事件時將拖曳物件的zIndex升高
stop事件則將拖曳物件的zIndex歸零
訂閱:
文章 (Atom)