Blackbing Playground
Blackbing Playground

記錄一些生活與工作的雜事,偶爾會寫一些前端網頁開發的心得


  • 首頁

  • 歸檔
Blackbing Playground

[Angular] grunt-usemin

發表於 2014-01-03 | 分類於 angular , grunt |

在使用 Angular generator 建立 project 相當的方便,

angular [app-name]```就可以裝完大部份所需要的東西,執行```grunt build```就會做好 uglify, minimize, packing, 等等的功能。其中一個對於線上環境很重要的功能就是 [usemin](https://github.com/yeoman/grunt-usemin)。功能很強大,設定有點多,因此我順便筆記一些一開始撞牆的地方。
1
2
3
4
5
6
7
8
9
10
11
#Blocks 打包某區塊裡頭的檔案(js/css)
例如你可以在 index.html 裡頭看到
``` html
<!-- build:js js/app.js -->
<script src="js/app.js"></script>
<script src="js/controllers/thing-controller.js"></script>
<script src="js/models/thing-model.js"></script>
<script src="js/views/thing-view.js"></script>
<!-- endbuild -->

這裡的設定是說在執行 usemin 時會將這幾隻 script 打包起來 output 成 js/app.js。因此如果你有額外新增加的程式需要一起打包的必須放在 block 裡頭,不然不會被打包進去。

不過在 build 完之後會發現有些檔案並沒有被打包進去,問題在於需要 compile 的程式(例如sass, coffee)會先被 compile 到 .tmp/ 的 folder 底下,因此預設的 search path 是搜尋不到這個檔案的。根據文件的說明:

1
<!-- build:<type>(alternate search path) <path> -->

用

1
2
3
4
例如:
```html
<!-- build:css({app,.tmp}) styles/main.css -->

(ㄜ…….這啥鬼格式?)

#revmap
rev 這個 task 會將 js/css/image/fonts 等做重新 rename 的動作,讓程式可以做到快取的優化,例如

會變成 ```foo.1234.png``` 這樣,而 usemin 的工作就是將 html 裡頭包含該檔案的路徑做取代。例如
1
2
3
```html
<img src="/images/toolset.png" alt="Yo, Grunt, Bower">

會變成

1
<img src="/images/75bab8-toolset.png" alt="Yo, Grunt, Bower">

不過由於在做 SPA(Single Page Application) 時會將很多 template view 拆開,所以我將一些其他的 view 分開像是這樣:

├── index.html
└── views
├── home.html
├── navbar.html
├── foo.html
└── bar.html

由於 這些 view 底下的 html 其實是要給 index.html 來使用的,因此他的路徑其實是從 root 開始算的,在開發階段其實都不會有問題,然而在 build 完之後就會發現圖片會找不到的情況。追了一下 log 才發現 usemin 雖然有 parse 這些 html 但並不會將 image tag 替換掉。其實想想也合理,因為根目錄的路徑不同啊!但這樣一來 template 享受不到 usemin 的好處,相當令人沮喪。

網路上好像找不到太到相關的問題,因此我就試著來解決,以下是我解決的步驟:

#####1. 在

"grunt-contrib-symlink": "~0.2.0"
1
#####2. 在```Gruntfile.js```加入以下的設定:

symlink: {
views:{
expand: true,
cwd: ‘<%= yeoman.dist %>/views/‘,
src: [‘*’],
dest: ‘<%= yeoman.dist %>/‘
}
}

1
#####3. 在```Gruntfile.js```加入以下的 task:

grunt.registerTask(‘clean-link’, function(target){
var yeoman = grunt.config.get(‘yeoman’);
var htmls = grunt.file.expand( {
}, yeoman.dist+’/*.html’).forEach( function(path){
if( grunt.file.isLink(path) )
grunt.file.delete(path);
});
});

1
#####4. 在 build task 裡頭的 ```'usemin'``` 改成

‘symlink:views’, //create symlink
‘usemin’,
‘clean-link’ //clear symlink
```

解決的方式是將 views/ 底下的 html 都建立 soft link 到根目錄,然後讓 usemin 去 parse,並且寫回 views/*.html ,最後將這些 symlink 清掉。

大概是這樣,grunt 真是很難懂。

Blackbing Playground

射後不理設計模式

發表於 2013-11-11 | 分類於 design pattern , finite state machine |

誒~其實這是我亂取的名字

AJAX Loading Loading ajax-loader (2).gif.gif)

大概有好一段時間,AJAX 的互動方式都會增加一個 Loading 的狀態顯示,在 Response 尚未回傳回來時,提醒使用者資料還在傳輸當中,當 Response 結束之後再顯示結果。這個 Loading 的圖示,大概就被當成網站很潮的 AJAX application 代表,像是 ajaxload.info 還有自動產生 Loading 圖示的網站。優點是讓使用者知道資料正在傳輸。但缺點是要等 server 端回傳回來資料才能修改 UI 的狀態讓使用者知道動作已經完成。但其實在某些情況時,使用者根本不需要知道這些狀態,只要系統能夠確保事情是完成的就好 (而且其實看久覺得蠻煩的,尤其是看到他不斷的在 Loading,或者是看到他閃了一下就不見,都會讓人覺得系統有問題)。

perform actions optimistically

Secrets to Lightning Fast Mobile Design 這篇投影片分享了 Instagram 如何讓 Mobile App 更快速的祕訣,其中有一項我覺得很簡單而且可以大幅改善效能的技巧:「perform actions optimistically」。

舉例來說,當使用者按下「Like」時,就會出現「Liked」的狀態,但其實資料還在傳輸。
Screen Shot 2013-11-11 at 下午4.47.08.png

當使用者留言時,就會先呈現留言完成的狀態,但其實資料還在傳輸。
Screen Shot 2013-11-11 at 下午4.48.29.png

所以這種方式其實是將 UI 的 feedback 直接給使用者,讓使用者「感覺」很快。

再來看一個例子:http://localtodos.com/ 這是一個 todo list 的應用程式,所有的資料都存在 client 端的 localStorage裡頭。由於不需要跟 server 端溝通,因此在做 新增/修改/刪除 時,沒有網路傳輸的延遲,當然就不需要做 loading 狀態的顯示,任何操作都可以直接反應給使用者。

那麼如果資料是存在 server 端,又要達到一樣的效果,該怎麼辦呢?其實只要將儲存的動作,改成「射後不理」就可以了。也就是說,使用者的操作並不理會 server 端的回應,只要保證「 server 端的資料與使用者的動作保持一致」即可。

射後不理(fire and forget)

基本上這種設計模式就是以呈現 UI 為主,系統在做什麼事情使用者不管,反正 UI 呈現怎樣,就應該要幫我處理掉。可以想成 UI 跟 backend 是不同步的,彼此只依靠 UI 來同步所該做的事情。

聽起來有點抽象,舉個例子來說,若今天有個資料可以讓使用者自由排序,當使用者進行拖拉的動作時,要將使用者排序的動作儲存起來,如果每次拖拉完成的動作都需要等待 server 端的回應,那就會造成 UI 上的不同步,進而影響到使用者操作時的困擾。這時就會需要射後不理這樣的設計模式來輔助使用者進行操作。

實作方式

聽起來不難,不過實作過程其實遇到很多很麻煩的事情,因此分享一些實作上的心得,為了簡化問題,我用 Like/Unlike 來舉例。需求很簡單:按下Like 按鈕之後切換 Like/Unlike 的狀態。BUT,如果連按兩次?三次?十次? UI 可以即時顯示,但要如何正確的跟 server 端溝通?如果在資料傳輸的過程中,使用者又改變了狀態?那怎麼辦?

  1. 狀態流程圖

    重點其實是狀態的改變,把狀態列出來畫成「狀態流程圖」就會比較好理解。
    Like-Unlike (1).png.png)

    • unknown: 未知狀態
    • fetch: 從 server 取得 Liked 資料
    • mismatch: 使用者按下「Like/Unlike」而且跟fetch的值不一樣
    • flying: 資料正在傳輸中

    所以如果資料傳輸回來時,發現使用者的狀態改變的話,又會再觸發 mismatch 跟 server 端 request。

  2. 發 request 的時機

    如果是 like/unlike 時就發送 request ,很快就會遇到一個問題,當使用者連點兩下時,就會同時發出 Like 和 Unlike,若狀態是根據 request callback 回來判斷的話,遇到「後發先至」的情況就會讓 UI 造成問題。因此「射後不理」的設計模式其實是可以避免這種情況發生的。

    發 request 的時機其實就是在使用者改變狀態時,且跟 fetch 回來的值不同時,為了避免使用者頻繁更新狀態而跟 server 端重複發 request,可以設一個 timeout 來檢查是否觸發 mismatch。

  3. server 端的回應確認 UI 是否保持一致

    最後,當 request callback 回來時,檢查使用者是否又很善變的改變了狀態,如果改變了,再重新做一次 mismatch,並且發 request。如此就可以循環整個流程。

有限狀態機

由於實作部分很難拆解出來,而且不同的 scenario 都會有不同的流程或解法,就不把程式碼貼出來獻醜了。我想表達的重點是「有限狀態機」,其實將流程圖畫出來之後就會發現很適合用「有限狀態機」來表達流程與狀態,而且也可以避免在流程中任意改變狀態(如果你是自己處理事件的觸發),除了幫助自己理解流程之外,程式碼也會比較好維護。

關於有限狀態機我也還在摸索階段,這是第一次嘗試應用在專案裡頭,有興趣歡迎再討論看看有哪些適合的案例。

Reference:

  • Secrets to Lightning Fast Mobile Design
Blackbing Playground

有限狀態機

發表於 2013-11-07 | 分類於 finite-state-machine , design pattern |

javascript 是 Event Based 的語言,因此可以很輕易的實作事件綁定來處理非同步的動作,為了將表現層與資料層分離,就會用「值」的改變來 trigger 事件。例如在 Backbone Model 裡頭可以做 change:value 的事件處理。例如:

1
book.on("change:title change:author", ...);

但是隨著應用程式越來越複雜,value 的 change 可以拿來當作事件的觸發,但流程並不會因此簡化,在設計程式時如果沒有一個更清晰的流程將會在 Event 裡頭的流程迷失方向,或寫出難以維護的程式碼。

Event pubsup

Event Pubsub,利用事件 publish/subscribe 的方式來做流程處理。但 pubsup只是針對事件的「綁定」與「觸發」,缺少了「狀態的轉換」。

有限狀態機(Finite State Machine)

「有限狀態機」是描述一種狀態的轉移,它強調過去狀態與當前狀態所引發的事件,因此可以將流程簡化到事件的處理之中。而且將流程簡化出來也能夠幫助自己在分析時更清楚地掌握流程處理。所以有限狀態機的重點是要將現有的流程簡化成一個可循環的狀態,利用狀態的轉移來觸發事件,相反地也可以觸發事件來轉移狀態。

javascript-state-machine

javascript-state-machine 是我覺得很好用的一套小 library ,程式碼也沒有很長,有興趣可以研究看看。裡頭有一個小 Demo,簡單解釋一下。

see demo: http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/example/

條件如下:

  1. 初始化事件:green
  2. warn: green -> yellow
  3. panic: green/yellow -> red
  4. 當 red 時,calm 事件觸發時要等待三秒才會恢復到 yellow
  5. 當 red 時,clear 事件觸發時要等待三秒才會恢復到 green
  6. 當 yellow 時,clear 事件觸發會恢復到 green

流程圖

看敘述有點難理解,可以直接看流程圖
Screen Shot 2013-11-07 at 下午1.09.47.png

事件:

  • start
  • warn
  • panic
  • calm
  • clear

流程:

  • reen
  • yellow
  • red

如果只看事件的話,只能依靠事件的觸發來控制流程,但是加上「狀態」之後,看起來就好理解多了,而且整個是一個可以循環的流程。把事件用箭頭連起來,就可以知道何時可以觸發哪一個事件。

流程圖中的箭頭代表「事件」轉換,框框代表「狀態」的轉移,所以當「狀態」改變,就會觸發「事件」,反之「事件」被觸發,就會改變「狀態」。例如「Warn事件」發生的時候,狀態就會從 green 轉移至 yellow;而「Panic事件」發生時,狀態就會改變成 red。

而設定的方式也很直覺,在 event 的地方設定好事件觸發時狀態如何改變。而 callbacks 可以在事件被觸發前/後 執行 callback unction。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
events: [
{ name: 'start', from: 'none', to: 'green' },
{ name: 'warn', from: 'green', to: 'yellow' },
{ name: 'panic', from: 'green', to: 'red' },
{ name: 'panic', from: 'yellow', to: 'red' },
{ name: 'calm', from: 'red', to: 'yellow' },
{ name: 'clear', from: 'red', to: 'green' },
{ name: 'clear', from: 'yellow', to: 'green' },
],
callbacks: {
onbeforestart: function(event, from, to) { log("STARTING UP"); },
onstart: function(event, from, to) { log("READY"); },
onbeforewarn: function(event, from, to) { log("START EVENT: warn!", true); },
onbeforepanic: function(event, from, to) { log("START EVENT: panic!", true); },
onbeforecalm: function(event, from, to) { log("START EVENT: calm!", true); },
onbeforeclear: function(event, from, to) { log("START EVENT: clear!", true); },
onwarn: function(event, from, to) { log("FINISH EVENT: warn!"); },
onpanic: function(event, from, to) { log("FINISH EVENT: panic!"); },
oncalm: function(event, from, to) { log("FINISH EVENT: calm!"); },
onclear: function(event, from, to) { log("FINISH EVENT: clear!"); },
onleavegreen: function(event, from, to) { log("LEAVE STATE: green"); },
onleaveyellow: function(event, from, to) { log("LEAVE STATE: yellow"); },
onleavered: function(event, from, to) { log("LEAVE STATE: red"); async(to); return false; },
ongreen: function(event, from, to) { log("ENTER STATE: green"); },
onyellow: function(event, from, to) { log("ENTER STATE: yellow"); },
onred: function(event, from, to) { log("ENTER STATE: red"); },
onchangestate: function(event, from, to) { log("CHANGED STATE: " + from + " to " + to); }
}

不過實際上,有限狀態機可以做什麼用?待續…

#延伸閱讀:

  • 阮一峰的网络日志 - JavaScript与有限状态机
  • Javascript State Machine v2.2
Blackbing Playground

Hello Logdown

發表於 2013-06-18 |

My First post in Logdown!

Nice Work!!!

Blackbing Playground

2013 JSDC Web Worker

發表於 2013-05-26 |

##JSDC 2013

第一次在這種大型研討會跟大家分享,看到這麼多熱血的前端工程師,真的是很高興,收獲頗多。我這次的主題主要是想分享在使用 Web Worker 時的觀念,雖然很多前輩都有分享過了,不過在實際專案上使用時還是有點綁手綁腳。因此我不從API角度來介紹 Web Worker ,而是從觀念與實際案例討論來理解 Web Worker。有任何問題歡迎提出討論。

閱讀全文 »
Blackbing Playground

Web Worker 經驗分享(二)

發表於 2013-04-15 |

本文章同步刊載於IT邦幫忙

那些年,我們一起讓瀏覽器當掉的日子

昨天提到了 Worker 就像是主從式架構一樣,有要求才有產出,而前後端的任務切割,就是在將商業邏輯與頁面呈現區隔開來。但隨著專案越來越複雜,前端越來越包山包海,我們好像一直不斷的在挑戰瀏覽器一樣,在前端做更多更複雜的事情。

chrome ooops

有了 Worker 之後,或許我們會開始回憶起「那些年,我們一起讓瀏覽器當掉的日子」。

回到主題,那麼到底有哪些情況會用到 Worker 呢?我們先來看看許多專家的說法:

Web Worker的使用案例

  • 影像辨識
  • 影音資料處理
  • 大量資料運算
  • 頻繁或大量的AJAX request
  • 較複雜的字串比對或分析
  • Local 端資料庫的存取
  • File IO (File Reader/Writer API)

以往這些較複雜的運算可能都要透過 server 端來處理,既然前端都可以處理這些事情了,那我們就可以直接在前端處理這些複雜運算,可以再度的節省 server 端的使用。而 Server 端最重要的 Database ,加上 HTML5 LocalStorage 與 IndexDB 可以在前端建立資料庫,拿來做一些簡單的單機系統也會更加容易。

但是這些很複雜的案例,並不是每個專案都有機會碰到,因此我想討論一些更common的案例。

前端可以處理的,就不在後端做

例如上傳圖片,以前都是直接整個檔案直接丟到server端做 resize, crop等等,現在流行前端直接做好再丟到後端。
例如上傳/下載某種檔案支援格式(.txt, .xls, .blabla),server端只要統一好格式,由前端組好在上傳到server端即可。

使用者操作時的「偷偷」動作

使用者在頻繁的操作系統時,如果此時要做一些偷偷背景動作,例如偷偷背景存資料,偷偷背景上傳檔案,讓使用者感覺「Wow,好快速。」例如:「文章自動儲存機制」,「程式碼高亮化(syntax highlight)」等。因為使用者正在操作系統,任何一個動作中斷都會讓使用者覺得系統當掉。

反正重點就是:優化/節省 Server Side 的使用,搾乾 Client Side 的效能(偷笑)。當然,這只是討論,如果有更好的使用案例都歡迎分享。

實作

有了這些基礎概念之後,我們就可以開始實作了。然而在實作上,我很快就遇到第一個問題。通常會需要用到 Worker 來幫忙的,可能會是比較複雜的專案,但中大型專案可能會用到 CoffeeScript 來加速開發的速度,用 RequireJS 來管理模組間的相依性,如果將 Worker 的 script 拆出去,馬上就遇到 Dependency 的問題。舉例來說:

1
worker = new Worker('/worker_path/my_worker.js');

這樣的路徑就失去了用 requirejs 的優勢,破壞了整個專案的 dependency ,如果為了用 Web Worker 而搞砸專案架構,那可是得不償失的,不過幸好,山不轉路轉。

Inline Worker

在 new Worker 時,丟進 Worker 的參數是一個路徑,那麼我們就可以動態產生一個 blob url 路徑,傳給Worker ,動態產生 Woker。

1
2
3
4
5
6
7
8
9
10
content = """
//It is javascript content
var dosomething = function(){
return 'ok dosomething';
};
"""
blobWorker = new Blob([content], {type:'application/javascript'})
blobWorker_url = URL.createObjectURL(blobWorker)
inlineWorker = new Worker(blobWorker_url)
URL.revokeObjectURL(blobWorker_url)

如上,我們就可以動態用 content 來建立 inlineWorker 。只要確保 content 的產生是沒有問題的,用 string 的方式將它讀入就可以建立 Worker。

另外 requireJS 也支援在 worker 裡頭使用,當你的 Worker 要做的事情很多時,可以用 RequireJS 來進行管理,參考requireJS webworker

Debug

Worker 裡頭沒有好用的 console 可以用,不過有 error 的 event 可以註冊。例如:

1
2
3
worker.addEventListener('error', function(error){
console.error(error)
});

另外也可以在 developer tool 裡頭的「Source」開啟「Workers: Pause on start」

debug worker

引用外部程式

Worker 是否可以引用外部程式? 答案是可以的,但需要注意的是它的限制是無法存取瀏覽器資源,所以跟 browser 相關的 API 例如 DOM 都不能用,所以不能使用 jQuery , Backbone 這種與 Browser 相依性很高的 Library (廢話)。

1
importScripts("http://underscorejs.org/underscore.js")

值得一提的是,

access 就會造成整個 Worker 直接死掉。
1
2
3
4
5
6
7
## 釋放Worker
如果確定Worker做完事了,需要結束 Woker 以釋放瀏覽器資源,可以呼叫``terminate``來終結 worker
``` javascript
worker.terminate()

或是直接在 Worker 裡頭自己主動結束

1
self.close()

其他

Worker 其實還定義了 Shared Worker ,可以在不同頁面共享 Worker 的資源,在此不介紹是因為我想不到有比較有意義的應用,有興趣深入瞭解的朋友可以參考 The Basics of Web Workers,裡面有基本的用法介紹。

Just do it

Web Worker 的 API 其實很簡單,難的是在實作上如何將這些動作拆開。建議可以慢慢的將一些動作移到 Worker 來處理,例如 AJAX request ,將資料處理與頁面 render 的程式分開。慢慢的就會更容易的掌握它。

不過不要以為 Web Worker 就這樣結束了,這篇文章其實只是個起點,實際應用在專案上,還會遇到很多問題(嘿嘿~),有任何問題都歡迎提出討論喔 ,我們 2013 JSDC 見。

廣告時間

「影分身好威喔!我也想要!」

HTC One 的 Camera 也可以快速建立多重影分身

參考資料

  1. http://dev.w3.org/html5/workers/
  2. https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers?redirectlocale=en-US&redirectslug=Using_web_workers
  3. http://blog.teamtreehouse.com/using-web-workers-to-speed-up-your-javascript-applications
  4. http://ejohn.org/blog/web-workers/
  5. http://www.html5rocks.com/en/tutorials/workers/basics/
  6. http://debuggable.com/posts/run-intense-js-without-freezing-the-browser:480f4dd6-f864-4f72-ae16-41cccbdd56cb
  7. http://stackoverflow.com/questions/2773682/what-are-the-use-cases-for-web-workers
  8. http://html5hacks.com/blog/2012/09/22/web-workers-basics-of-the-web-browsers-ui-thread/
  9. http://www.html5rocks.com/en/tutorials/workers/basics/#toc-enviornment-subworkers
  10. http://blogs.msdn.com/b/ie/archive/2011/07/01/web-workers-in-ie10-background-javascript-makes-web-apps-faster.aspx
  11. http://blogs.msdn.com/b/davrous/archive/2011/07/15/introduction-to-the-html5-web-workers-the-javascript-multithreading-approach.aspx
  12. http://msdn.microsoft.com/en-us/hh549259.aspx
  13. http://stackoverflow.com/questions/11871452/can-web-workers-utilize-100-of-a-multi-core-cpu?rq=1
  14. http://www.smartjava.org/content/html5-easily-parallelize-jobs-using-web-workers-and-threadpool
Blackbing Playground

Web Worker 經驗分享(一)

發表於 2013-04-14 |

本文章同步刊載於IT邦幫忙

各位「網路工作者」大家好!

It's you! web worker

Web Worker 是由 W3C 以及 WHATWG 共同制定出來的API,讓 javascript 可以獨立在背景執行而不會影響到原來的HTML頁面,Web Worker 可以更有效率的執行前端程式。

聽起來很厲害,總是在跟效能搏鬥的前端工程師就會傻傻的想跳進這個坑(如我),但是由於沒有整體性的瞭解這個東西,只參考API想要改善任何效能上的問題就會有點心有餘而力不足,最後還是放棄,然後跟自己說:

「唉~算了啦~這麼不好用,等他成熟一點再說吧!」。

因此想跟大家分享一下我在使用 Web Worker上的一點點心得,以及在服用 Worker 之前應該要有的觀念。本文章希望從實作的角度來讓大家了解 Web Worker 到底可以做什麼,而不僅止於 API 的介紹。

閱讀全文 »
Blackbing Playground

moving cursor in VIM

發表於 2012-11-14 |

##鍵盤好好用

對電腦工作者而言,滑鼠絕對是很重要的工具,不過在Vim裡頭,鍵盤才是你最好的朋友,但如何利用鍵盤在程式碼之間遊走,而不是只依靠「上下左右」,我們需要記住幾個小指令。這篇也是想整理起來給自己看的,若有整理不詳還請包涵或分享。

##VIM指令鍵

以下列出我常用的指令,太複雜的我也記不起來@@,像是左上下右h j k l我還是不習慣用,還是直接用鍵盤的上下左右,不過這幾個指令也很夠用了。

  • ^ 該行第一個字元
  • <Home> 該行第一個字元
  • $ 該行最後一個字元
  • <End> 該行最後一個字元
  • % 跳至程式碼區塊的開頭或結尾,例如在「{」上按下「%」就會跳到「}」
  • w 跳至下一個字串 (包含特殊字元) 的第一個字元
  • W 跳至下一個字串 (不包含特殊字元) 的第一個字元
  • b 跳至上一個字串 (包含特殊字元) 的第一個字元
  • B 跳至上一個字串 (不包含特殊字元) 的第一個字元
  • e 跳至下一個字串 (包含特殊字元) 的最後一個字元
  • E 跳至下一個字串 (不包含特殊字元) 的最後一個字元
  • gg 文件第一行
  • G 文件最後一行
  • {number}G 跳至{數字}行數,例如「23G」就會跳到第23行

其中w, W, b, B 很實用,用習慣了在追程式碼的時候還蠻快速的。

##搜尋

直接搜尋文件中的字串也很方便,就像按下Ctrl+F會跳出搜尋框一樣。

  • /keyword 直接搜尋文件中的keyword
  • n 搜尋模式中為下一個關鍵字
  • N 搜尋模式中為上一個關鍵字

##Easy-motion

Easy-motion 是更強的快速跳躍,Vim必備元件之一,不過需要注意的是,他預設是用<Leader>鍵來觸發指令,我初次使用時卻覺得異常的慢,後來把Leader_key改掉就變快了,應該是<Leader>鍵有觸發其他的動作吧!

我是設為,

1
let g:EasyMotion_leader_key = ','

所以要做motion時就按下,w就可以做快速跳躍了。

  • ,w 往後跳躍
  • ,b 往前跳躍

##碎碎念

Vim真的是開發者的優秀編輯器,只是初學會的確被一堆指令嚇到,雖然滑鼠很方便,但手不用離開鍵盤真的可以節省更多時間,習慣之後用其它編輯器都會不自覺的想要按指令來處理XD。

Blackbing Playground

自動整理照片策略(windows版本)

發表於 2012-10-11 |

這篇文章是幫助windows使用者整理照片,請參考本blog的 自動整理照片策略

##Windows使用者服用

不用害怕,你只需要click而已。

雖然我很久沒用windows了,不過還是得照顧一下windows族群的朋友。而且久沒寫windows command line,寫起來果然是很掰咖。

閱讀全文 »
Blackbing Playground

自動整理照片策略

發表於 2012-10-08 |

auto-org-photo-strategy

##懶惰是進步的原動力
現在相機越來越強,照片也越來越大,每次要整理照片真是有點累,除了要忍受硬碟空間的不足之外,還要忍受檔案輸入輸出的速度,然後有時也不可能天天都在整理照片,因此每次都會堆個幾天(月)?再一次整理照片,但累積越久要整理就越痛苦,光是要把照片分日期行程命名就是一個很令人暈眩的事情。

閱讀全文 »
1234…11
Bingo Yang

Bingo Yang

記錄一些生活與工作的雜事,偶爾會寫一些前端網頁開發的心得

109 文章
61 分類
RSS
© 2018 Bingo Yang
由 Hexo 強力驅動
主題 - NexT.Muse