在成为一名不专业的 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) 时可选.
附: FreeMarker API
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) {
jQuery("#clickMe").click {
jQuery.get("/path", { data, textStatus, _ ->
println("$textStatus")
})
}
}
复制代码
附: jQuery API
后记
有了上述知识之后, 会写 Kotlin 的你, 就能进行简单的前端开发了, 也许你的某个想法可以就此实现第一步.
Kotlin 有一个官方的 FullStack Demo, 使用的是 React 做前端, 如果你有兴趣学点新技术的话也可以试试.
@Uraka.Lee