在成為一名不專業的 Android 開發之前, 做的是不專業的前端開發工作. 大致的工作就是寫點 Web 頁面, JS/CSS, 寫點 Spring 的 Servlet. 搞 Android 之後這塊就沒怎麼摸過了, 所以技術棧還是非常古老的 jQuery + Spring + Velocity.
自從 IDEA 爸爸搞出了 Kotlin, 試了一下開發 iOS 非常崩潰. 但全棧之心蠢蠢欲動, 感覺還是可以搞點事情. 所以就稍微揀了一下, 記錄下來供大家參考.
前端的組成部分
開啟一個 HTML 頁面, 我們通常能看到如下幾類元素.
DOM (頁面)
HTML 是各種 tag 的巢狀結構, 在根元素之下是 HEAD 和 BODY. BODY 裡面是頁面結構, 現代的 Web 開發通常不會直接把內容直接寫到 DOM 裡, 所以一般來說頁面裡只有結構, 沒有內容.
CSS
HEAD 裡面會有 style 和 xyz.css, 這類東西叫 CSS (層疊式樣式表), 用來控制內容的樣式/排版. 需要注意的是 CSS 對於元素的影響也是巢狀的, 可以在 Chrome 的開發者工具中檢視一個元素的樣式究竟受到哪些 CSS 的影響. CSS 的用法有兩種, 一種是在 tag 上引用 class: class="style1 style2"
, 另一種是在 tag 上直接寫 style: style="xyz: abc, ijk: def"
.
JavaScript
現在好像流行放在 BODY 的最後面, 這裡就是小前端的邏輯. 如果把瀏覽器當作客戶端, DOM 是 Android 的 layout, CSS 是 Android 的 style, JavaScript 是 Android 的邏輯程式碼.
遠古時代的前端開發技術
DOM
上文提到的 Velocity 就是可以用來動態生成頁面的工具, 這類工具叫做模板引擎. 模板引擎允許開發人員定義一些變數, 在伺服器返回頁面時它會把變數的值替換到模板中, 實現了同一份程式碼顯示不同的內容, 比如: Hello, ${userName}
會跟不同的使用者打招呼.
CSS
最新的不太瞭解, 而且作為一個開發人員其實也不太擅長樣式/排版的東西. 我建議大家看一下 BootStrap/中文版, 是 Twitter 的開發人員開源的前端開發框架, 在沒有 UI 的時候可以用這個做出視覺上過得去的頁面.
響應式佈局 & 柵格系統
BootStrap 的一大特色是提供了支援響應式佈局的簡單方法, 被稱為柵格系統.
響應式佈局的意思就是在不同螢幕寬度下同一套程式碼樣式/排版不同. 可以試一下官方樣例中的任何一個頁面, 嘗試改變螢幕寬度從顯示器大小到手機大小, 會看到神奇的效果.
BootStrap 把顯示寬度等分為 12 份, 可以通過 container + col 的 class 簡單的分割頁面, 並在各種解析度下保證效果.
JavaScript
目前我用的比較熟的只有 jQuery 了. 雖然是一個遠古時代的庫, 但目前仍有大批使用者, 可能是因為用起來簡單吧. 主要概念有:
- selector. 可以根據 id 或者 class 篩選 DOM 元素, 可以理解為 Android 的 findViewById. 拿到元素之後可以填充內容/更改樣式/監聽事件等.
- ajax. 中文翻譯忘了... 總之就是非同步的向伺服器發請求, 拿到資料之後部分重新整理頁面, 這樣體驗比較好.
遠古時代 x Kotlin
DOM x Ktor x FreeMarker
Kotlin 出了一個官方的 Servlet 開發框架叫 Ktor. 和 Spring 對比之類的我就不做了, 不知道 Spring 發展到什麼程度了.
Ktor 的 Quick Start 裡使用的模板引擎是 FreeMarker, 簡單用的話和 Velocity 差不多, 我就沒有折騰直接用了. Ktor 也有對於 Velocity 的支援, 在新建 Ktor 專案(需要在 IDEA 中安裝 Ktor 的 plugin) 時可選.
Response
返回模板內容是一種 response, Ktor 還提供 responseText
以及 response(object)
, 後者會把 object 序列化為 json 結構, 相當方便.
Routnig
Routing 是 Ktor 用來分發請求的機制. 任何一個來自客戶端的請求通過 router 分發到對應的程式碼, 通過這樣的方式把相關的程式碼聚到一起, 把不相關的程式碼分開. 在 Ktor 中沒有看到類似 Spring 中的 Controller 的概念(印象中 Spring 雖然也有路由的概念, 但程式碼層面上是用 Controller 的).
routing {
get("/") {
call.respondText("Hello World!", ContentType.Text.Plain)
}
}
複製程式碼
靜態資源的 routing 形如:
...
static("/static") {
resources("static")
}
...
複製程式碼
沒有依賴注入
Ktor 目前沒有內建的依賴注入, 也就是說依賴需要顯式建立, 也許這也是為什麼 Ktor 沒有 Controller 概念的原因.
CSS 還是 BootStrap
作為一個沒有 UI 支援的開發人員, BootStrap 就是最好的選擇.
JavaScript x Kotlin
能用 Kotlin 寫 JS 解決了我對 JS 的大部分怨念, 雖然聽說現在用 VSCode 開發 JS 也很爽.
Kotlin Call JS
Kotlin 提供了幾種呼叫 JS 的方法, 比如 js("java-script code")
, 當然這不是一個好的方式.
還有 Dynamic Type, 可以認為是 JS 專用的, 變數宣告為 dynamic 之後, 其後續呼叫都會返回 dynamic 型別, 相關程式碼會原封不動的拷貝成 JS 程式碼.
比較好方式是 external 修飾符. 使用 external 修飾符可以把一個已有的 JS 方法/類宣告成 Kotlin 可檢查的型別, 比如: external fun alert(message: Any?): Unit
對應了一個瀏覽器自帶的 window.alert()
方法. 宣告上述 external 方法之後, 在 Kotlin 程式碼裡可以直接呼叫 alert()
通過 external 這種方式, Kotlin 可以直接使用很多第三方的 JS 庫, 比如 jQuery. 使用方式是為第三方 JS 庫生成一系列的 external, 被稱為 header, 有點類似於使用第三方 C/C++ 庫時需要的標頭檔案. ts2kt 工具可以做這個事情, Thanks TypeScript, 這個工具實際上是把 TypeScript 的標頭檔案轉成了 Kotlin 的標頭檔案.
有了這個標頭檔案之後, 我們就可以直接在 Kotlin 程式碼裡調 JS 了, 比如:
fun main(args: Array<String>) {
jQuery("#clickMe").click {
jQuery.get("/path", { data, textStatus, _ ->
println("$textStatus")
})
}
}
複製程式碼
附: jQuery API
後記
有了上述知識之後, 會寫 Kotlin 的你, 就能進行簡單的前端開發了, 也許你的某個想法可以就此實現第一步.
Kotlin 有一個官方的 FullStack Demo, 使用的是 React 做前端, 如果你有興趣學點新技術的話也可以試試.
@Uraka.Lee