@atry
2016-08-09T13:18:08.000000Z
字数 2643
阅读 4203
Binding.scala 的基本用法很像 ReactJS ,也是通过编写模板把数据映射成 HTML 。
首先,你需要设置项目的构建脚本。Binding.scala 就是普通的 Scala.js 库,按普通的 Scala.js 项目配置方式即可。具体参考 Scala.js 的教程或者TodoMVC的源码仓库。
修改你的 build.sbt 文件,加入以下两行
libraryDependencies += "com.thoughtworks.binding" %%% "dom" % "latest.release"addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
@domdef spinner(i: Var[Int]) = {<div><button onclick={ event: Event => i := i.get - 1 }>-</button>{ i.bind.toString }<button onclick={ event: Event => i := i.get + 1 }>+</button></div>}@domdef render = {val i = Var(0)<div>{ spinner(i).bind }控件当前值是:{ i.bind.toString }</div>}
你可以在Binding.scala的DEMO网站实际运行一下试试。
Scala 代码的语法和 ECMAScript 6 很接近。有 JavaScript 经验的同学只要参考
From ES6 to Scala 就可以迁移到 Scala.js 了。
以上 Scala 代码创建了两个 HTML 模板,其中 spinner 是个数字选择组件,render 是页面的内容。Binding.scala 支持 Scala 代码和 HTML 模板混合编写,所以 onclick={...} 把一个 Scala 函数设置给了 HTML 属性 onclick 。
上述代码用到了 Binding.scala 的几个API:
@dom 把方法标记成绑定表达式,在这个方法内可以编写 HTML 模板、可以使用 .bind 监听其他 HTML 模板或变量。Binding 是绑定表达式。上面代码的 spinner(i)、render 和 i 都是 Binding 。
Binding.bind 用来监听绑定表达式。xxx.bind的含义是“each time xxx changes”。比如 @dom def j = i.bind + 5 表示每当 i 改变时,j也改变,j的值是 i 的值加5。
注意:bind表示绑定表达式之间的依赖关系,所以只能写在绑定表达式的内部。bind不是普通的函数!
Var 是可以被监听的变量,Var继承了Binding。上面代码中的 i 就是个 Var。 Var.bind 继承自 Binding.bind,表示要监听变量的值。Var.get 获取变量的当前值,不能写在绑定表达式中。:= 对变量的赋值,并重新计算所有依赖该变量的绑定表达式,不能写在绑定表达式中。注意:{ event: Event => i := i.get + 1 }没加 @dom ,是个普通的函数而不是绑定表达式,所以其中可以使用 get 和 := 。
这两个 HTML 模板之间传递了绑定变量 i 作为参数。所以,当 spinner 内的 onclick 修改 i 时,spinner 和 render 中的 i.bind 都会触发,实现了类似双向绑定的效果。
编写完功能后,你需要在 main 中把 render 渲染出来。
@JsExport def main() = {dom.render(document.body, render)}
dom.render 接受两个参数,第一个参数表示要把模板渲染到哪个位置,第二个参数是将要渲染的模板。最后在静态 HTML 中调用 main() 方法:
<script type="text/javascript"> SampleMain().main() </script>
这样一来整个程序就写完了。
复杂的网页上往往会有重复的元素,可以把数据保存到 Vars 容器,然后用 for / yield 渲染。
比如
@dom def render = {val logs = Vars("Hello", "Binding.scala")<div>{ for { log <- logs } yield <div>{ log }</div> }</div>}
以上代码通过 for / yield 语句渲染了两行文字,你可以在Binding.scala的DEMO网站实际运行一下试试
Vars 是可以被监听的容器。所以,每当 Vars 的内容修改时,渲染出的网页也会自动修改:
@dom def render = {val logs = Vars("Input code:")val input = <input type="text"/>val submitHandler = { event: Event =>logs.get += input.valuelogs.get += js.eval(input.value).toStringinput.value = ""event.preventDefault()}<form onsubmit={ submitHandler }>{ for { log <- logs } yield <div>{ log }</div> }{ input }</form>}
以上代码实现了一个代码控制台,你可以在输入框中输入代码,按下回车键,就能看到代码执行结果。
你可以在Binding.scala的DEMO网站实际运行一下试试。
Vars.get 类似 Var.get,用来容器的当前值,返回值是个 scala.collection.mutable.Buffer。
所以你还可以对 Var.get 取得的当前值调用 Buffer 的 += 等各种方法,直接进行修改容器的当前值。
当你修改这个 Buffer 时,会触发 Binding.scala 自动执行对应操作,把修改集映射到 for / yield 生成的页面上。
比如,logs.get += input.value 添加了一个字符串,那么渲染出的网页上也会添加一行包含该字符串的 <div> ,而不需要修改网页上原有的其他部分。
注意,Vars.get 、 += 就像 Var.get 和 := 一样,也不能在@dom绑定表达式或代码模板中调用,而只能在其他函数中调用。
比如以上代码的 submitHandler 回调函数不是一个 @dom 函数,所以可以在其中修改 logs。