使用WebSharper和F#开发移动应用

时间:2022-02-22 19:08:08

Formlet是最近一套来自学术界的形式体系,它是WebSharper不可分割的一部分。而WebSharper则是最初实现Formlet的几个框架之一。Formlet代表了一流的、类型安全的、可组合的数据表单,它与你可能一直在用的ASP.NET或其他Web框架中的非严格类型的方法有着很大的不同。WebSharper实现中包含了从属formlet,其中formlet的一部分从属于另一部分,例如从属于多选项的下拉框或是输入框中的输入值;flowlets是一种定制的布局,它用来在一个formlet计算表达式或F#一元结构中以一种类似向导的顺序方式一步步渲染每一个formlet.

下面是一个简单的formlet,它返回一个字符串值,其中各种不同的增强被增量式应用于其上http://www.wx-jr.com

let nameF =

Controls.Input “”

|> Validator.IsNotEmpty “Empty name not allowed”

|> Enhance.WithValidationIcon

|> Enhance.WithTextLabel “Name”

Formlet可以被映射到任意类型的返回值上,例如一个百分比输入控件可能会返回0到100之间的浮点数值,或者一个组合框可能会生成可区分联合(discriminated union)中的某种类型(可能有也可能没有标记值)。你可以用许多方式将多个较小的formelet组合成更大的formlet.最简单的方法是使用Formlet.Yield函数将任意类型的值封装成该类型的formlet,并结合<*>操作符组合两个(或通过连续调用组合多个)formlet:

Formlet.Yield (fun v1 v2 … vn -> <compose all v's>)

<*> formlet1

<*> formlet2



<*> formletn

下面的例子展示了Formlet如何获取个人信息(姓名和邮件),并进行基本的客户端验证http://www.sd-ju.com

type Person = {

Name: string

Email: string

}

[<JavaScript>]

let PersonFormlet () : Formlet<Person> =

let nameF =

Controls.Input “”

|> Validator.IsNotEmpty “Empty name not allowed”

|> Enhance.WithValidationIcon

|> Enhance.WithTextLabel “Name”

let emailF =

Controls.Input “”

|> Validator.IsEmail “Please enter valid email address”

|> Enhance.WithValidationIcon

|> Enhance.WithTextLabel “Email”

Formlet.Yield (fun name email -> { Name = name; Email = email })

<*> nameF

<*> emailF

|> Enhance.WithSubmitAndResetButtons

|> Enhance.WithLegend “Add a New Person”

|> Enhance.WithFormContainer

图2显示了嵌入在sitelet页面后的结果。注意页面样式是由从属的CSS资源提供的,它会在引用formlet代码时自动加载到页面中(事实上,准确地说是发生在调用Enhance.WithFormContainer时)。WebSharper中高级的依赖性跟踪功能会在页面处于服务状态时为其自动收集所依赖的资源。这个功能非常便利,它为使用各种不同的WebSharper扩展和使用第三方的JavaScript库节省了大量的时间和精力,并且它从根本上消除了手工跟踪页面所需资源的需要http://www.wx-jr.com

上面formlet例子中的[<JavaScript>]标注指示WebSharper将代码段翻译为JavaScript.每个控件中增强的验证器均为WebSharper formlet库的一部分,并且它们提供客户端验证,因此Validator.IsEmail将确保在formlet在到达一种可接受状态前只键入了合法的邮件地址。你还可以调用自定义的函数或者通过进一步加强手头的formlet来提供额外的验证。如果某个函数被标记为[<Rpc>]并从客户端代码中调用,那么WebSharper将会生成代码执行RPC(远程过程调用)并自动处理客户端和服务端的值传递。你可以无缝使用任意复杂的F#对象,如嵌套列表(nested list)、映射(map)、集合(set)或序列(sequence),而不用担心它们在内部被如何映射。这统一了客户端和服务端代码,并且大大地减少了开发时间。事实上,客户端和服务端代码在开发过程中通常位于同一个F#文件中,只是它们被组织进同一命名空间下的不同模块中http://www.wx-jr.com

许多WebSharper模式可以用来开发客户端-服务器应用程序,我们通常建议使用sitelet和formlet一起工作,并提供各种编码指导来最大限度地提高开发人员的工作效率,但是你也可以借助WebSharper在大量的ASP.NET代码基础上开发混合型的应用程序,或者基于WebSharper的功能改善现有的ASP.NET应用程序http://www.sd-ju.com

从抽象中构建来满足所需

有时,你可能需要跳出标准WebSharper formlet库的范围来为应用程序实现表单(或者整个UI)。例如,你可能想要使用不同的输入控件来渲染formlet,因为简单的CSS重写可能不能够满足你所想要的外观和感觉。其它时候,你想重用现有的JavaScript控件库,如Ext JS,YUI,或是jQuery UI来得到更精细的外观和感觉。WebSharper为上述的第三方库提供了大量的扩展包,其中一些扩展包还提供了formlet抽象。

下面的简短例子在jQuery移动扩展中使用了Formlet,通过在Formlet.Do中使用flowlet布局以及组合熟悉的Formlet.Yield一起完成了两个步骤的登录序列http://www.sd-ju.com

let loginSequenceF =

Formlet.Do {

let! username, password, remember =

Formlet.Yield (fun user pass remember -> user, pass, remember)

<*> (Controls.TextField “” Theme.C “Username: ”

|> Validator.IsNotEmpty “Username cannot be empty!”)

<*> (Controls.Password “” Theme.C “Password: ”

|> Validator.IsRegexMatch “^[1-4]{4,}[0-9]$” “The password is wrong!”)

<*> Controls.Checkbox true Theme.C “Keep me logged in ”

|> Enhance.WithSubmitButton “Log in” Theme.C

let rememberText =

if remember then“”else“not ”do! Formlet.OfElement (fun _ ->

Div [

H3 [Text (“Welcome ” + username + “!”)]

P [Text (“We will ” + rememberText + “keep you logged in.”)]

])

}

|> Formlet.Flowlet

你可以使用必要的jQuery移动功能将登录序列组合进HTML标记中(可以使用多几行的代码将其很好地抽象出来),然后添加到sitelet页面上:

Div [HTML5.Attr.Data “role” “page”] -< [

Div [HTML5.Attr.Data “role” “header”] -< [

H1 [Text “WebSharper Formlets for jQuery Mobile”]>

]

Div [HTML5.Attr.Data “role” “content”] -< [

loginSequenceF

]