Blackbing Playground
Blackbing Playground

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


  • 首頁

  • 歸檔
Blackbing Playground

react-taggable-input

發表於 2016-12-12 | 分類於 react , react.js , TaggableInput , react-mention , contenteditable , react-taggableinput , react-taggable-input | 1 Comment

最近碰到一個有趣的 UI,不曉得該怎麼命名,類似像 facebook 的 @ 或是 twitter 可以在文中 tag 標籤。我就稱它為 TaggableInput。

文長,若您想直接看結論請 電梯往下

因為平常在 facebook, twitter 用的很習慣,看起來跟一般的 input 行為也沒有什麼不同,介面也很好學習。不過前端工程師一看到就知道案情不單純。首先 input,textarea element 都只能接受純文字,如果用這兩個 element 要做到這個功能一定是不可能。以下是幾個類似的 library。

react-tagsinput


inspect 看一下就可以知道他的實作方式是在後面多一個 input element,輸入完就 append tag。但這只適合處理 tag,無法結合文字輸入,而且他的 trigger 目的其實是要將文字斷開,所以 trigger 點會是像 Space, , 這樣的字元。

react-mention

react-mention 剛看到時覺得有點訝異,這套竟然能在 input 和 textarea 裡頭呈現不同的樣式,於是我很好奇的偷看他怎麼做的。

沒想到他竟然隨著編輯 textarea 動態產生一個 div,並且隨著不同的 tag 可以 apply 不同的樣式,稍微 trace 他的 source 發現他是利用 radium 這套 lib 動態算出樣式然後把 textarea 疊在一起。像是這樣。

這真是讓我太驚訝了,前端工程師真是創意無極限誒。原本我想要很快速地用這一個套件來實作這個 UI 功能,但這套的缺點是他跟 recommand list 的 UI 綁的太緊(我們有自己的 recommand list 與邏輯),而且這種功能通常都需要透過 ajax 來 query list 的部分,要客製化不太容易,而且用了一下覺得 style 的部分還是沒有很輕鬆。

draft-js mention

這套是 facebook 出品的,UI 做的很細膩,很多細節都處理完了,但我覺得不需要為了這個功能把 draft-js 整包拉進來用,所以先擱著。

contenteditable

最後我偷看了一下 facebook 怎麼做的(早就應該偷看了),結果我發現一絲曙光,contenteditable。這樣一切都 make sense 了。既可以 input,又可以 apply style。

can I use?

IE 11 以下都支援,那就開始實作吧。

需求

整理一下這個 input 所需要的功能:

  1. placeholder:placeholder。
  2. maxLength:字串長度。
  3. trigger: 按下某個符號會 trigger recommand list。
  4. Esc, Space: 要可以取消 trigger recommand list。
  5. onSubmit: 送出輸入資料。
  6. 要可以從 recommand list callback 回 input 並取代使用者輸入的字串。

總之,一般 <input /> element 的功能都要有,並且要可以 trigger 字元。

jsx

接下來定義一下 jsx 的介面:

1
2
3
4
5
6
7
8
9
10
11
<TaggableInput
className="input"
placeHolder="請輸入文字"
trigger="#"
maxLength={ 100 }
onKeyDown={ this.props.onKeyDown }
handleSubmit={ this.handleSubmit }
onTrigger={ this.handleTrigger }
onChange={ this.handleChange }
onSubmit={ this.handleSubmit }
/>

問題

原本以為 trigger 某一個字元應該不難,沒想到實作之後才發現問題一拖拉庫,這篇的心得其實重點在記錄遇到的問題們。

Key Event

首先 DOM Level 3 有一個 Input Event 可以處理當值改變的時候會觸發這個事件,而且查了一下 can i use input event 看起來也都沒問題。

那麼這跟 KeyPress, KeyUp 等 event 有什麼不同呢? 主要是 Keyboard 相關的 event 都是處理跟鍵盤有關的事件,但內容物的修改不只從 Keyboard 來,還有滑鼠,觸控,等等。Input Event 的優點就是可以處理任何 input value 的改變。

看起來很美好,於是我就一路寫下去感覺沒什麼太大的問題,沒想到開始測試 IE 之後才發現問題大條了,IE 系列竟然不支援 contenteditable 的 Input Event。查了一下還蠻多災情的:

  • Make onChange work for contenteditable
  • input event not firing in IE10 or IE11?
  • input event does not fire on div with contenteditable set
  • IE系でinputイベントが発火しないのをなんとかしてみる(ついでにIME入力中は発火しないイベントも追加)

回頭重新看 MDN Input Event 才發現他真的有提到 IE 不支援 contenteditable 的 input Event。

DOMCharacterDataModified

胡亂查資料的時候看到 DOMCharacterDataModified ,覺得好像有一絲曙光,仔細一查才知道他屬於 Mutation Event,但已經 Deprecated,取而代之的是 Mutation Observer。但 Mutation Observer 依然不支援 IE10(含以下),相關討論可以參考 Stack overflow 的討論 contenteditable change events。

以下節錄討論的內容:

Consider using MutationObserver. These observers are designed to react to changes in the DOM, and as a performant replacement to Mutation Events.

Pros:

Fires when any change occurs, which is difficult to achieve by listening to key events as suggested by other answers. For example, all of these work well: drag & drop, italicizing, copy/cut/paste through context menu.
Designed with performance in mind.
Simple, straightforward code. It’s a lot easier to understand and debug code that listens to one event rather than code that listens to 10 events.
Google has an excellent mutation summary library which makes using MutationObservers very easy.
Cons:

Requires a very recent version of Firefox (14.0+), Chrome (18+), or IE (11+).
New API to understand
Not a lot of information available yet on best practices or case studies

contenteditable change eventsConsider using MutationObserver

總之 MutationObserver 是未來的曙光,想要解決所有可能的 Input 問題,包含拖拉,複製貼上,滑鼠操作,觸控,右鍵選單等等等等。但這位成員有點太新了,API 也有很大部分的改變,IE 的 support 也不完整,部分瀏覽器還需要 prefix,blablabla….所以先擱著備用。

Keydown/KeyUp/KeyPress

那麼我用老方法總可以吧?KeyDown/Keyup event 可以拿到 KeyCode,感覺土法煉鋼還是有可能辦得到的?於是我就土法煉鋼也是刻出了一個版本。結果問題又來了…

KeyDown

首先 KeyDown 會在按下任何按鍵時觸發,但 KeyDown 時還不會拿到 change 之後的結果,因此 KeyDown 的處理時機無法達到目的。

KeyUp

KeyUp 的問題在於每個按鍵都會被觸發,包括 Meta,Ctrl,Shift,但當使用者按下 Shift+# 之後的行為有兩種可能:

  1. KeyUp # -> key 拿到 3
  2. Keyup Shift -> key 拿到 Shift

這在實作上就會遇到很大的問題,因為 KeyUp 的順序會造成取到的 key 值不同。

KeyCode 229

另外在 windows 上開啟中文輸入法之後按下 # 會拿到 KeyCode 229,查了一下也是災情慘重:

  • 黑大的 jQuery - 中文輸入法與KeyDown/KeyPress事件
  • Is it OK to ignore keydown events with keyCode = 229?

有興趣的話可以在 windows 打開測試 keycode 的網頁,切換英數輸入法之後輸入 #,會印出

keydown keyCode=16 which=16 charCode=0
keydown keyCode=51 (3) which=51 (3) charCode=0
keypress keyCode=35 (#) which=35 (#) charCode=35 (#)
keyup keyCode=51 (3) which=51 (3) charCode=0

開啟注音輸入法之後輸入 #,會印出

keydown keyCode=16 which=16 charCode=0

#keydown keyCode=229 which=229 charCode=0
textInput data=#
keyup keyCode=16 which=16 charCode=0

主要原因是因為在 windows 上用輸入中英文的習慣是按下 shift+按鍵,按照 spec 來說,輸入法開啟狀態時,回應 229 其實是沒錯的。在 Mac 反而沒這個問題,因為你必須切換輸入法才能按下半形的 #。

react-taggable-input

最後終於推出 react-taggable-input,如此一來我們就能在 input 時塞任何的 html 了(劇情急轉直下)。

那麼最後怎麼處理 trigger 的問題?

value change

主要概念就是「在 keyup 之後從目前游標往前找最近的 trigger 字元」,而不是想辦法在 keydown keyup 時檢查是否是有 trigger 字元。

嗯,概念看起來很簡單,但我可是拐了好多彎才想到啊。

當然其中還有一些比較特別的處理:

  • 利用 CompositionEvent API來偵測使用者正在開啟輸入法模式。
  • 利用 Selection Api 偵測和操作使用者選取範圍的內容修改。
  • 取得 contenteditable 的游標位置。
  • Mac 可以直接按下全形的 # 來輸入,不用切換輸入法。
  • 由於在 KeyUp 處理,因此理論上支援 IE 系列瀏覽器。

其他細節有興趣的人請直接看 source code 吧,

DEMO


http://blog.blackbing.net/react-taggable-input/

工商服務時間

鉅亨網推出 股市 Talk 可以設定自己常用的自選股,讓你可以邊看股票邊討論股票,還有新聞,影音等,還有超強大的線圖,堪稱是目前網頁版最強的看盤軟體。

看看我們一個小功能都可以執著成這樣你就知道我們有多細膩了。

Reference

  • Diffrence between keyup keydown keypress and input events
  • input event does not fire on div with contenteditable set
  • contenteditable change events
  • keyCode property of key events
Blackbing Playground

終於脫離 logdown 了

發表於 2016-12-06 | 0 Comments

改用 hexo,可喜可賀!以上!

Blackbing Playground

我們用 react-native 開發鉅亨網 app

發表於 2016-07-24 | 0 Comments

身為一個 frontend developer,在看到 react-native 問世之後一直對 react-native 很有興趣,最近終於有機會可以碰到了,也因此才有這篇 勸世文 心得,本文主要想記錄一下開發到目前為止所踩過的坑,為還在 survey 技術的團隊開路。

適合用 react-native 開發嗎?

在接觸 react-native 之前,其實我們對開發 app 是還沒有信心的,一來這東西太新,二來我們也沒有實際開發過 app 的經驗,很多 UI 效果都要 survey 才知道到底做不做的到,就算 native support 也不知道 react-native 有沒有 support。一直到我們真的把 app 上架之後,才覺得比較有一點信心。但在開始之前,先確認一下是否有對 react-native 誤解:

不是 write once, run everywhere,而是 learn once, write anywhere

在大多數的情況下,你可以讓 Android/IOS 共用同一份 code,但這不代表你可以爽爽的不管平台問題就可以實作出功能。兩個平台畢竟還是有一些不樣的 user experience,例如 iPhone 沒有 back button,所以你需要為了 android 多處理 back button 的 behavior (BackAndroid)。也因此在程式裡頭還是免不了得判斷 Platform。

例如:

1
2
3
const styles = StyleSheet.create({
height: (Platform.OS === 'ios') ? 200 : 100,
});

不過很方便的地方在於因為 react 本身就是個 view 的 engine,因此要將 component 拆開是輕而易舉的事情,而 react-native 可以讓你很輕鬆的將程式分開。

例如原本我們有一隻 NewsDetailPager.js 的 component,但由於在實作上 Android 和 ios 上面的行為遇到不同的問題。後來就將這個 component 拆成

  • NewsDetailPgger.android.js
  • NewsDetailPager.ios.js

就可以讓兩種平台在 compile 時就只 build 相對應的程式,也許之後也會有

  • NewsDetailPager.ms.js
  • NewsDetailPager.tizen.js

註:Facebook’s React Native gets backing from Microsoft and Samsung

總之,用 react-native 開發也是得考慮不同 platform 的問題,雖然 react-native 官方已經解決大多數的繁瑣的部分,但你仍須思考不同平台是否適合同一套 UI/邏輯。

react-native 不是 webview

不要以為你原本就用 react 開發 mobile web 之後就可以移植到 react-native,基本上可共用的部分可能只有 pure 的商業邏輯,跟 view 有關的部分都會需要重寫。

react-native 的優點

整理一下用 react-native 開發的優點:

debug 非常方便:

基本上如果只是 view 的 update,react-native 都已經做好 hot reload 了,只要程式碼修改就會局部 rerender。

React 大幅降低學習成本

如果你原本就熟悉 react 的開發流程,從 react 跳進 react-native 很快,因為原本的經驗是可以繼續累積的,包含 react, flux, redux, 各種 react performance 調效的經驗都是有用的。

感受不到跟寫 web 有太大的差別

一開始最讓我驚喜的其實是用 react-native 開發我真的不覺得我在開發 app,反而就像是多了一種特異的 browser 而已,而且 debug 也是用熟悉的 console 在 debug。react-native-debugger 也可以看到 jsx 的 tree。

專心寫你的商業邏輯

基本上 react-native 已經處理掉大部分的效能問題,例如 listView 已經處理了大量列表只會顯示使用者看到的部份而已。這讓開發者可以專注於產品功能的實現,不用花費太多心力在調整 UI 上的效能。

react-native 的生態圈非常完整

awesome-react-native 有整理了幾乎目前有的 resource ,包含教學,components 等等,看也看不完的東西。open source 的世界就是這麼迷人,based on 全世界工程師的開發與回饋造就健壯的社群。

Frontend resource

藉由 react-native,自此 frontend Engineer 可以支援 app 的開發,開發UI 上的經驗可以共用,對於組織內人力的配置也可以更加靈活彈性。

UI Explorer

UI Explorer 列出了幾乎所有 react-native 支援的 component 與範例,看 UIExplorer 有時比文件寫得更完整。

react-native 的缺點

雖然開發到現在覺得很滿意,不過還是得列一下缺點。

掰咖的 style

react-native 用 javascript 來實現 css 的設計(style),但並不是支援所有的屬性,例如 z-index (0.29 之後支援 ios)。

沒有 image-background,沒有 background-repeat 等等。不過雖然少了這些東西,大部分的需求還是可以想辦法實現的,也可以藉由 react-native-svg 做到很多漂亮的 UI。

各種踩坑

一開始在用 navigator 時用了 NavigationExperimental,但由於是 experimental,每次 react-native 更新都有 api change,因此每次都要隨著更新。

像是這個新聞內頁左右翻動的功能,看似很簡單,但因為資料是動態的,所以嘗試了好幾種 pager 的實作,最後是用 react-native-viewpager

升級總是很痛苦

react-native 每兩週就會 realease 一個版本,這使得我們在開發到第一次上架成功之間就升級了無數次,第一個版本是 0.21,到目前為止已經是 0.30,中間有幾次升級是非常重大的更新,很多相依的 package 也要跟著更新才能順利更新上去。

小結

react-native 讓前端工程師可以站在巨人的肩膀上更快速的開發,雖然到目前為止在實作中還是有許多地雷,但相信在 open source 的基礎下會更加的健壯,若您在開發的 app 功能都沒有跳脫 UI Explorer 的範例,相信要用 react-native 來開發可以相對的降低開發的時間與成本。

鉅亨網 App

  • Android 下載連結
  • IOS 下載連結

另外 react-native showcase 也有我們的身影喔!(不過後來因為 showcase 的政策更新被移掉了)。

歡迎討論 react-native 開發的相關問題。

工商服務時間

歡迎有熱情於互聯網科技、財經資訊、金融理財的專家人才加入鉅亨網。

  • Senior backend engineer
  • Backend engineer
  • Frontend engineer
Blackbing Playground

[react] react-numeral-input

發表於 2015-08-19 | 分類於 react , input , numeral-input | 0 Comments

react-numeral-input

之前寫了一個 react-numeral-input,主要是可以所見即所得的處理數字的格式,例如 100000 直接顯示為 100,000。原本的想法是將所有的輸入都轉成數字,然後將輸入的數字加上數字的格式。

不過這樣的作法會造成一個問題,就是當使用者在開啟輸入法時,打的任何值都會被吃掉(看起來像是鍵盤沒用的樣子)。網路上找到的解法大部分都是去做字串取代,但這樣無法解決問題。

input type=”number”

html 的 <input type="number" > 無法顯示非數字,因此在做這個 component 時就知道不能用這個 type 了。

ime-mode: disabled

於是查了一下發現看起來最簡單的方法就是 disable ime-mode,但 ime-mode 只有在 firefox 和 IE 上能動。沒辦法跨瀏覽器。

keycode 229

接著發現當使用者用輸入法輸入時,收到的 keyCode 都是 229,也就是說是可以檢查使用者目前是開啟輸入法的,也可以提醒使用者關閉輸入法已確保正確的輸入。但麻煩的是還要額外提醒使用者的 UI 或者 notice。
React-numeral-input_by_blackbing.jpg

User Feedback

轉個念一想,其實問題是在使用者輸入時,沒有對應的 user feedback 給他,才會造成誤解欄位無法輸入的情況,因此保留不正確的格式好像也不是一個問題?
螢幕快照_2015-08-19_下午4_42_28(2).jpg

這樣就不需要去考慮輸入法什麼問題,類似這種所見即所得的工具,可以改變使用者的輸入,但要避免讓使用者誤解「輸入 -> 輸出沒反應。」

結論

如此要解決的問題就顯得容易的多,當你在輸入時開啟輸入法,還是可以輸入,但程式不會將你輸入錯的值吃掉,而是返回給試用者,至於是否要顯示 error message,則交給系統自己決定即可。看似簡單的問題,卻繞了一大圈回來才想到解法。

DEMO

有興趣的人可以玩玩看 react-numeral-input,或是直接安裝

1
npm install react-numeral-input --save-dev
Blackbing Playground

[javascript] 利用 Deferred 處理動態的順序性任務

發表於 2015-07-06 | 分類於 javascript , Deferred , pipe | 0 Comments

前情提要

之前寫了一篇 利用 Deferred 處理順序性任務,主要是利用 Deferred 來避免 callback 寫法的缺點。

不過在實務上,可能會遇到更複雜一點的情況,例如:

pipe array flow.png

這張圖的意思是要確保任務是 A->B->C 的執行順序,而且當 A,B,C 有任一個 fail 就會停止,不會再執行下去。我們直接來看應該要怎麼處理這樣的程式。

範例

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
var a = $.Deferred();
var b = $.Deferred();
var c = $.Deferred();
var checkA = function() {
console.log('checkA');
return a.reject();
};
var checkB = function() {
console.log('checkB');
return b.resolve();
};
var checkC = function() {
console.log('checkC');
return c.reject();
};
var checkAll = function(){
var _dfr = $.Deferred().resolve();
_dfr = _dfr
.pipe(checkA)
.pipe(checkB)
.pipe(checkC);
return _dfr.promise();
};
checkAll().done(function() {
return console.log('checkAll done');
}).fail(function() {
return console.log('checkAll fail');
});

為了簡化程式,我直接在 checkA/B/C 的 function 中回傳 Deferred reject or resolve。上述的例子可以直接看結果。
可以看到結果只會印出

1
2
"checkA"
"checkAll fail"

是因為 checkA 執行時就被 reject 了,因此不會再繼續執行下去。您可以自己試試看將 reject 改成 resolve 看一下執行的結果會變成怎麼樣。

Dynamic task function

實務操作上 task 也許會是動態的,我們可以很簡單的將任務指派成一個 array 的形式,例如:

1
var funList = [checkA, checkB, checkC];

然後將 checkAll 的任務串起來

1
2
3
4
5
6
7
8
var checkAll = function(){
var _dfr = $.Deferred().resolve();
var funList = [checkA, checkB, checkC];
for(var i=0; i<funList.length; i++){
_dfr = _dfr.pipe(funList[i]);
}
return _dfr.promise();
};

最後的程式碼結果請猛擊這裡

結論

要注意的是不能用 jQuery.when,when 是一次發出去執行,會等到全部做完才會回來。

Reference

  • jQuery Deferred with an array of functions
Blackbing Playground

[react] selection auto-complete component

發表於 2015-04-15 | 分類於 react , react-components , auto-complete , Selection | 0 Comments

最近在找一個 selection 的 react component,但希望可以支援 auto-complete,找了好幾個不是整合有問題,就是彈性不夠,試了幾個都不太好整合。後來找到這個,http://jedwatson.github.io/react-select/,蠻不錯的 UI,想要的功能也都支援。特此記錄一下。

react-select

demo

螢幕快照 2015-04-15 下午2.45.56.png
蠻喜歡這種 UI 的,兼具 input 和 select 的控制項。

以下是其他類似的,但用過都還是有缺點

  1. https://github.com/asbjornenge/react-datalist
    利用 html5 datalist,用 react 的特性其實很好操作,缺點是 支援瀏覽器有限(http://caniuse.com/#search=datalist),polyfill 太醜然後某些 action 操作不太一樣。
  2. https://github.com/fmoo/react-typeahead
    看到 typeahead 我以為是 twitter 的 typeahead 的 react 版本,後來看了 sourcecode 才發現作者是重頭實做了一次 typeahead ,但是很多部分跟原本的 typeahead 不太一樣。操作起來綁手綁腳的。
  3. https://github.com/eliseumds/react-autocomplete
    這個 repository 取名取得很好不過跟 npm 的 react-autocomplete 又不一樣,然後 npm 的 react-autocomplete 的命名其實是 combobox ,而且沒在維護,連 source code 也不在 github 上了。

  4. https://github.com/prometheusresearch/react-selectbox
    因為星星數不夠多,所以根本沒用過。

以上。雖然網路資源很多,但是找起來好像在查 paper 的感覺,希望有幫助到有相關需求的人。

Blackbing Playground

Secrets in npm package.json

發表於 2015-01-19 | 分類於 npm , 講個秘訣 | 0 Comments

講個秘訣

在用 npm 來管理 node package 時,愚昧如我只會用 npm install 來 install package,在歷經一些痛苦之後決定好好來看一下 package.json 的秘密。

dependencies V.S. devDependencies

區分專案的開發時的模組相依性。一般來說開發時都會用 npm i $PACKAGE_NAME --save-dev 這樣就會設定成該模組的 devDependency。但如果參數是給 --save 就會是 dependency。這是用來區別 production mode 時不需要下載 devDependency 的 package。

需要注意的是,npm install 預設會載入 devDependency 的 package,若是在 production mode 時,要做
npm i --production 指定只載入 dependency 的 package,如此就不會多載入一些開發才需要用到的 package。

npm scripts

不知道有沒有人跟我一樣,看到 Caesar 大大這個討論串,多想三秒,其實可以不用 grunt & gulp.,才發現原來 npm 可以自訂 scripts,然後傻傻的打 npm watch,結果不能執行,後來查了一下才知道 npm 有預設的指令,如果要執行自訂的指令要用 npm run xxx來執行。所以可以搭配一些 shell 指令來簡單的做你想做的事情。

pre/post scripts

然後在看 npm scripts 時看到一個蠻有趣的用法。

Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript).

簡單來說可以分開執行 script 的順序,在做複雜的指令還蠻好用的。 例如你可以自訂:

1
2
3
4
5
{
"scripts": {
"bingo": "echo Bingo"
}
}

所以當執行 npm bingo 就會 echo Bingo,接著加上 pre/post 的話,例如:

1
2
3
4
5
6
7
{
"scripts": {
"bingo": "echo Bingo",
"prebingo": "echo Hello",
"postbingo": "echo World"
}
}

這樣執行 npm bingo 就會 echo

1
2
3
Hello
Bingo
World

舉例來說,我會搭配 bower 來管理前端需要用的 package,我就可以加上 postinstall 的指令來做 bower install。

1
2
3
4
5
{
"scripts": {
"postinstall": "bower install"
}
}

當執行 npm install 之後就會接著做 bower install。

所以 ReadME 就不用再寫 Step1, Step2, …。只要 npm install 就可以搞定啦,而且 jenkins 的 job 設定也可以變的比較一致性了,專案自己該做的事情就寫在這些 scripts 即可。回過頭來說,「多想三秒,你真的可以不用 grunt & gulp.」

package version control

不知道有沒有人注意到,在執行 npm install $PACKAGE_NAME 時,他會指定成 “^1.2.3”,這是 follow https://github.com/npm/node-semver 的版本號規則。

需要注意的是預設的 “^1.2.3”,意思是 [ '>=1.2.3-0', '<2.0.0-0' ],所以若 package 版本有更新,會自己升上去。最近幾次有遇到 jenkins 自己莫名其妙 build fail 就是因為版本不同而造成的問題。建議可以改成 “~1.2.3” [ '>=1.2.3', '<1.3.0' ] 或是寫死版本 “=1.2.3”,再視專案而定更新就好。團隊開發時版本的控制很重要,沒有指定好大家拉不同的 code 常常會造成浪費時間的 debug。其他更詳細的用法就在參考 https://github.com/npm/node-semver 囉。

npm outdated

有空可以執行 npm outdated 來檢查 package 的更新,視情況而決定是否要更新 package。建議是開 feature branch 來做 upgrade package,沒問題再 merge 回去。

以上,這些大概是開發常會遇到的一些心得與秘訣,如果想看更詳細的解釋就請直接看 doc 啦。

References:

  • https://docs.npmjs.com/files/package.json
  • https://docs.npmjs.com/misc/scripts
  • https://github.com/npm/node-semver
Blackbing Playground

Wedding Party Hackday

發表於 2014-12-25 | 0 Comments

16.jpg
最近完成了終身大事,也終於有點時間記錄一下了,身為一個宅宅工程師,我堅持自己的婚禮也要充斥一點宅味,當然也要感謝我的老婆容忍我的任性(疑~)。

其實很久以前就想過婚禮時可以做哪些系統了,有鑑於大家都說到時候不會有時間做這些事情,於是我提早開始準備我要做的系統。

互動式婚紗照片

我一直覺得婚紗本又重又難收藏,所以我很早就想把婚紗照直接用螢幕輸出,但只做播放太無聊了,所以我想要加入一些互動的元素,很直覺就想到用「motion detect」來做翻頁。

gest.js

gest.js這套 Library 可以用 camera 來辨識揮手的動作,辨識上下左右。試了一下辨識度還不錯。

jssor slider

要找適合的 slider library 反而找比較久,因為我希望可以支援上下左右的滑動效果,自動播放時也有一些客製化的特效,但大部分的 slide show 都只有左右滑動,最後找到這個客製化程度蠻高的 library jssor slider ,實際使用時其實他也沒辦法直接用上下滑動,所以我有修改了他的原始碼,讓他可以支援動態改變左右滑動與上下滑動。

最後就生出來這個版本了:DEMO,有興趣玩的人只要把 /image/photos/ 底下的照片換掉即可。有空我再寫 README。

10850072_10152841915926539_3126894732238031620_n.jpg

現場是用 iMac 顯示,然後在桌上弄點布置這樣,真是頗具巧思(自己說)。不過事實證明,沒有人介紹的話其實鮮少有人會發現可以用手控制,然後應該是小孩比較有興趣而已XD。

婚禮留言板

這個是我一直想做的東西,每次參加婚禮在開場前賓客都會不知道要幹嘛,早到的朋友會有點無聊,為了增加一點互動性,應該安排一些小活動給大家玩,類似的東西就是實體的留言箱,大家發一張小卡,然後上面些一些祝福的話,最後新人抽獎出來之類,不過因為沒有辦法看到大家的留言,少了一點即時的參與感。於是我又打算 web 化(沒辦法,我只會這個XD),讓賓客用手機留言,然後即時顯示在投影布幕上。

桌卡

桌卡的範本來自於 mybigday (個人覺得不好用),不過我用了他的桌卡範本改成我要的格式,放了 QR code 和連結上去。
桌卡

手機留言

c21c5f114d9bbcba443f0d334b36f5ed (1).jpg

留言板

螢幕快照 2014-12-25 13.20.21.png

抽獎活動

留言當然要用點誘因來讓大家留言囉,於是我做了一個透過手機抽獎,可以讓主持人邀請重要嘉賓抽獎的部分。
c21c5f114d9bbcba443f0d334b36f5ed.jpg

最後的重頭戲就是抽獎了,由於前陣子很愛玩 ranger ,而且他的抽獎動畫實在是太可愛了,所以我就把裡面的動畫擷取出來做抽獎,效果不錯(自己說)。
螢幕快照 2014-12-25 13.19.11.png

小插曲

千古不變的定律, live demo 一定會出狀況,當天果然也是,原因是我以為 facebookid 都會拿到一串數字,結果我自己白痴塞了一些預設的 string id 進去,本來是拿數字 id 來取 mod 所以就出狀況了。好在我有堅強的 HTC FE 團隊協助我當場的 debug(hug)。
1619141_10201994217896298_4293646646054564328_n.jpg

10806202_10201994262017401_6262181042209528548_n.jpg

總結

  1. QR code 很不普及。
  2. 桌卡做的太假掰,有人以為是餐廳的根本不想理。
  3. 非常非常需要 promote,下次有機會(疑?)應該要請工作人員一桌一桌介紹或施加壓力(?)留言,要讓大家更有參與感一點,最後的抽獎才會 high。
  4. 其實只是搞死自己而已,其實我程式早在兩個月前就準備好了,不過婚禮前幾個禮拜測試發現 firebase 的 auth 部分改版了,結果為了要測 auth 的部分又花了一些時間修改程式。中間一度想要放棄這個活動。下次有機會(疑?)就乖乖的走完流成就好了。
  5. 我老婆好票釀。
  6. 謝謝大家的參與,大家下次見(疑?)
  7. 我愛我老婆。

62.jpg

最後順便打個廣告,如果有人對這個留言系統和抽獎程式有興趣的話請來信聯絡,保證以友情價情義相挺。

Blackbing Playground

[ReactJS] tips of Writting JSX with CoffeeScript

發表於 2014-08-08 | 分類於 jsx , ReactJS , react , CoffeeScript , Coffee | 0 Comments

由於一開始我沒有認真看 JSX (而且也很懶得看)就開始使用 coffeescript 來寫 React 了,所以一直沒有去搞懂 JSX 到底要怎麼寫,直到最近才開始認真使用 JSX 來開發,詳看上集。關於 jsx 的 tip 其實官方有介紹一些技巧與注意事項:可以參考 React Tips Introduction。

因為自己習慣用 coffee 的關係,所以會遇到一些小問題,這篇文章主要紀錄一下用 coffee 寫 react 需要注意的地方與心得,本篇文章的程式碼也都是 coffeescript。

browserify

強烈建議一定要使用 browserify ,官方寫的 todomvc-flux就是用 browserify 來打包程式的,用了 browserify 之後就可以用 coffeeify 和 reactify 來 compile 程式了。

關於 browserify 的設定可以參考我的專案設定 https://github.com/blackbing/htccs-webapp/blob/master/gulp/tasks/browserify.coffee

jsx header

若程式之中有需要做 reactify 的程式要在第一行加上這行,讓 reactify 認得要 parse jsx 語法。

1
`/** @jsx React.DOM */`

jsx component

jsx 特有的語法就是用 element tag name 來當語法,例如:

1
2
3
4
5
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});

用 coffee 來撰寫時就會用到 ``` 來轉成 javascript 再交給 reactify 來處理。

1
2
3
4
HelloMessage = React.createClass(
render: ()->
return `<div>Hello {this.props.name}</div>`
}

this and @

coffee 用 @ 代表 this,但小心不要在 jsx 語法裡頭用 @,因為被 `` 包住的部分會被當成 javascript 來處理,coffeeify不會去處理這部分。舉例來說。

1
2
3
4
5
6
HelloMessage = React.createClass(
onClick: ->
alert 'onClick'
render: ()->
`<div onClick={@onClick}>Hello {@props.name}</div>`
}

如此 @onClick 就會變成 undefined。應該要改成 this.onClick 來處理。像這樣:

1
2
3
4
5
6
HelloMessage = React.createClass(
onClick: ->
alert 'onClick'
render: ()->
`<div onClick={this.onClick}>Hello {this.props.name}</div>`
}

every component need a root parent

每一個 component 都需要一個 parent 來包住,例如你不能這樣寫 jsx:

1
2
3
4
5
6
HelloMessage = React.createClass(
render: ()->
`<div>Hello foo</div>
<div>Hello bar</div>
<div>Hello foobar</div>`
}

而是要用一個 element 包住:

1
2
3
4
5
6
7
8
HelloMessage = React.createClass(
render: ()->
`<div>
<div>Hello foo</div>
<div>Hello bar</div>
<div>Hello foobar</div>
</div>`
}

由於這可能會影響 HTML 的結構,需要跟 Designer 確定一些實做細節。

Empty text node will wrap by \

例如

1
`<th>type{foo}</th>`

會變成這樣

這可能會跟原本預期的不太一樣,為了避免樣式問題,可能要跟 Designer 確認避免產生空的文字節點。

Sperate component if there’s any logic control

用了 jsx 之後會發現遇到邏輯部分的程式會不太好寫。例如用 js/coffee 來寫的話會像是這樣。

1
2
3
4
5
6
7
8
9
10
11
HelloMessage = React.createClass(
render: ()->
R.div className="form-component"
if type is 'image'
R.img src:data.src
else if type is 'input'
if inputType is 'text'
R.input type:"text"
else if inputType is 'radio'
R.input type:"radio"
#...(skip)

而用 jsx 要在一個 render function 做這些判斷會看起來很可怕。建議盡量拆 component,拆 component 是不用錢的。由於 component 都是單一物件的設計,所以盡可能的將一個 component 的邏輯簡化。如上例,可以將裡頭的 if-else 判斷拆出去 FormItem,像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FormItem = React.createClass
render: ->
data = @props.data
if data.type is 'image'
`<img src={data.src} />`
else if data.type is 'input'
if data.inputType is 'text'
`<input type="text" value={data.value} />`
else if data.inputType is 'radio'
`<input type="radio" value={data.value} />`
HelloMessage = React.createClass(
render: ()->
`<div className="form-component"
<FormItem data={data} />
</div>`
#...(skip)

這是一個很簡單的技巧也可以將 component 快速的拆開,不要嘗試在一個 component 裡頭包入太複雜的邏輯判斷。另一個好處是可以針對單一個 component 來做 unit-test。

false in jsx

false 在 jsx 裡頭有些不同的意義,在 http://facebook.github.io/react/tips/false-in-jsx.html 有說明,不過因為很重要所以要講三次。

其中最重要的是 false element

1
`<div>{false}</div>`

這樣會變成 <div></div>,成為一個空的節點。在做一些邏輯判斷時還蠻好用的。

Never modify DOM by yourself

如果你開始使用 React 了,請戒掉用 jquery 操作 DOM 的「壞習慣」。真的,一開始會很不習慣,例如addClass('loading') 太方便了,但是摻雜使用的後果就是很難 debug。建議要做任何 DOM 的操作都交給 state/props 來決定。

如果有其他使用 React 的小技巧也歡迎分享喔~

Blackbing Playground

[ReactJS] jsx or coffee style

發表於 2014-08-05 | 分類於 react , ReactJS , jsx , Coffee , CoffeeScript | 0 Comments

JSX

在寫 ReactJS 時,官方建議使用 jsx 這樣的語法來處理 html,這有點像是 template engine,不知道什麼是 jsx 的同學可以在 jsx compiler 玩玩看。jsx 其實不是必要的東西,如果你開心的話也可以直接用

jsx 充滿了疑惑,要做一些邏輯性的操作(例如 if-else, foo-loop)等等,相對的有點麻煩。
1
2
3
4
5
6
7
8
9
10
11
12
13
後來看到了一篇文章,推薦用 coffeescript 的特性來直接撰寫 React component:[React, JSX, and CoffeeScript](http://neugierig.org/software/blog/2014/02/react-jsx-coffeescript.html)。文章提到用 coffeescript 的特性來操作 component 會更加的得心應手,於是我也動手把 component 直接改成 coffee style。寫出來的程式大概長成這樣:
```coffeescript
R.div id: 'list-view', className: 'view tab-pane fade in active',
if listType is 'foo'
R.div className: 'back', '←'
R.p className: 'alert alert-warning',
R.i className: 'fa fa-exclamation-circle'
if listType is 'bar'
R.span null, 'Hello world'
else
R.span null, 'Magic!'

優點

利用縮排來 beautify 程式

1
2
3
4
R = React.DOM
R.p null,
R.a href:'foo', 'bar' # note omitted comma here
R.a href:'foo2', rel:'nofollow', 'second link'

利用 foo-loop 來產生 template

1
2
3
R.ol null,
for result in @results
R.li key:result.id, result.text

相比之下用 jsx 就囉唆許多:http://facebook.github.io/react/docs/multiple-components.html

寫 if-else 像是在喝水的簡單

1
2
3
4
5
6
7
8
9
10
11
if not @state.editing
R.div null,
@props.text
' '
R.span className:'link-button mini-button', onClick:@edit, 'change'
else
R.div style:{position:'relative'},
R.input
style:{position:'absolute', top:-16, left:-7}
type:'text', ref:'text', defaultValue:@props.text
onKeyUp:@onKey, onBlur:@finishEdit

相比之下 jsx 的 if-else 限制很多:http://facebook.github.io/react/tips/if-else-in-JSX.html

缺點

但是一直到最近我放棄了,所以我來說說 coffee style 的缺點。

無法使用在太複雜的 DOM 結構

其實可想而知,若DOM結構複雜的話,這樣做會搞死自己,雖然我們自以為對 javascript/coffee 非常熟稔,但人眼終究敵不過 template 的複雜度。這是一段我曾經寫的 component 的程式,坦白說這個結構沒有很複雜,但我看第二次的時候我自己都想殺了我自己,大家可以笑笑:

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
35
36
R.fieldset(className:"form-group #{ex_className}",
R.legend( {className:"scheduler-border"}, item.name),
R.div( {className:"table-responsive"},
R.table( {className:"table table-hover"},
R.tbody(null,
for d_items, key in item.dynamic_item
console.log d_items
R.tr(null,
for i of d_items
d_item = d_items[i]
if d_item.type is 'dropdown'
R.td(null, DropdownItem(item:d_item))
else
R.td(null, TextItem( item: d_item))
R.td(null,
R.button( {type:"button",className:"btn btn-default btn-sm",
onClick: do(key)=>
=> @removeItem(key)
},
R.i( {className:"glyphicon glyphicon-remove"})
)
)
)
)
),
R.div(null,
R.button( {
type:"button"
className:"btn btn-info btn-xs extend form-add"
onClick: @addItem
},
R.i( {className:"glyphicon glyphicon-plus"})
)
)
)
)

難以維護

由於 coffee 終究是 javascript,用 coffee 來寫基本上就只是在寫程式,一開始我對於可以使用 underscore 之類的 library 來寫 react component 感到很興奮,最後發現這根本沒辦法維護。比方說,我們可以這樣用

1
React.DOM.div null, foo.bar.map( (r)-> fruit[r]).join(', ')

看起來很簡單,而且寫起來很乾淨,但是當 template 摻雜著太多的邏輯,可就不好玩了,因為你很難控制團隊中大家會怎麼去使用這些東西,其實 template 應該還是回歸單純,只能接收 data,顯示 data。邏輯等等的東西應該都不要跟 template 有太多瓜葛。

結論

在經過一段時間的實做之後,我認為這些缺點非常致命,因此我不建議使用 coffee 來寫 react component,雖然說官方也提到 jsx 不是必要,但若是團隊合作的專案之中,建議還是乖乖的使用 jsx 來處理 template,盡量將邏輯與 template 分開。

下次會分享一些使用 jsx 的小技巧。

12…11
Bingo Yang

Bingo Yang

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

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