Позвольте показать вам простейший законченный пример использующий сайтлеты WebSharperа, которые будут в релизе 2.1.
Определим вебсайт из двух страниц (и двух действий):
view raw SiteletExample1.fs This Gist brought to you by GitHub.
Теперь давайте смешаем (mash up) шаблон для вебсайта, используя встроенные в F# комбинаторы HTML. Шаблон – это просто функция получающая тело и декорирующая его:
Надо отметить две вещи:
Теперь определим сайтлеты:
HomePage и AboutUsPage – одностраничные сайтлеты с одним URL и одним действием. Они комбинируются в вебсайт при помощи оператора Sum.
Теперь немножко административного boilerplate:
И все! Давайте на это посмотрим:


Пока все хорошо. У страниц те URLы, которые мы ожидали и работают ссылки в меню.
То, что описано выше, может быть выполнено любым достойным вебфреймворком. Давайте раздвинем границы и чуть-чуть это приправим. Добавим несколько строк F#, которые будут компилироваться в JavaScript:
Тут есть кнопка, которая при нажатии меняет надпись на себе. И тут есть элемент управления.
Теперь, несмотря на то, что Кнопка целиком живет на клиенте (фактически, создает узлы DOM), Элемент управления выполняет квантовый переход: конструктор выполняется на сервере, а тело – на клиенте.
Но это означает, что можно воспользоваться Элементом управления, чтобы склеить клиент и сервер. Давайте изменим страницу AboutUs:
Вот оно. Теперь пользователь увидит нажимаемую кнопку с JavaScript, реализованную на F#, прямо там, где вы этого ожидаете. Никакого беспокойства о тегах script, никакой ловли зависимостей, нет беспокойства с “ondocumentready”, все просто работает:

Ниже полный листинг. Как только выйдет версия 2.1, вы сможете запустить это сами. Оставайтесь с нами!
Определим вебсайт из двух страниц (и двух действий):
type Action = | Home | AboutUs
view raw SiteletExample1.fs This Gist brought to you by GitHub.
Теперь давайте смешаем (mash up) шаблон для вебсайта, используя встроенные в F# комбинаторы HTML. Шаблон – это просто функция получающая тело и декорирующая его:
module View = let ( => ) a b = A [HRef b] -< [Text a] let Page title body = PageContent <| fun ctx -> { Page.Default with Title = Some title Body = H1 [Text title] :: UL [ LI ["Home" => ctx.Link Home] LI ["AboutUs" => ctx.Link AboutUs] ] :: body }
Надо отметить две вещи:
- F# позволяет определять ваш собственный синтаксис и пример свободно это использует (=>).
- Вместо ручного генерирования URLов, вы просите контекст создать ссылку на действие. Это обеспечивает безопасность: если переименовать действие Home, то проект перестанет компилироваться; если переместить его на другой URL, ссылки останутся корректными.
Теперь определим сайтлеты:
module Site = let HomePage = View.Page "Home" [ Div [Text "Welcome to our website!"] ] |> Sitelet.Content "/" Home let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] ] |> Sitelet.Content "/about" AboutUs let Main = Sitelet.Sum [ HomePage AboutUsPage ]
HomePage и AboutUsPage – одностраничные сайтлеты с одним URL и одним действием. Они комбинируются в вебсайт при помощи оператора Sum.
Теперь немножко административного boilerplate:
type Website() = interface IWebsite<Action> with member this.Actions = [] member this.Sitelet = Site.Main [<assembly: WebsiteAttribute(typeof<Website>)>] do ()
И все! Давайте на это посмотрим:


Пока все хорошо. У страниц те URLы, которые мы ожидали и работают ссылки в меню.
То, что описано выше, может быть выполнено любым достойным вебфреймворком. Давайте раздвинем границы и чуть-чуть это приправим. Добавим несколько строк F#, которые будут компилироваться в JavaScript:
module Client = open IntelliFactory.WebSharper.Html [<JavaScript>] let Button label = Button [Text label] |>! OnClick (fun button _ -> button.Text <- "CLICKED") type ButtonControl(label: string) = inherit Web.Control() new () = new ButtonControl("unlabelled") [<JavaScript>] override this.Body = Button label :> _
Тут есть кнопка, которая при нажатии меняет надпись на себе. И тут есть элемент управления.
Теперь, несмотря на то, что Кнопка целиком живет на клиенте (фактически, создает узлы DOM), Элемент управления выполняет квантовый переход: конструктор выполняется на сервере, а тело – на клиенте.
Но это означает, что можно воспользоваться Элементом управления, чтобы склеить клиент и сервер. Давайте изменим страницу AboutUs:
let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] Div [new Client.ButtonControl("Click me!")] ] |> Sitelet.Content "/about" AboutUs
Вот оно. Теперь пользователь увидит нажимаемую кнопку с JavaScript, реализованную на F#, прямо там, где вы этого ожидаете. Никакого беспокойства о тегах script, никакой ловли зависимостей, нет беспокойства с “ondocumentready”, все просто работает:

Ниже полный листинг. Как только выйдет версия 2.1, вы сможете запустить это сами. Оставайтесь с нами!
namespace WebSharperSiteletsProject open System open System.IO open System.Web open IntelliFactory.Html open IntelliFactory.WebSharper open IntelliFactory.WebSharper.Sitelets type Action = | Home | AboutUs module View = let ( => ) a b = A [HRef b] -< [Text a] let Page title body = PageContent <| fun ctx -> { Page.Default with Title = Some title Body = H1 [Text title] :: UL [ LI ["Home" => ctx.Link Home] LI ["AboutUs" => ctx.Link AboutUs] ] :: body } module Client = open IntelliFactory.WebSharper.Html [<JavaScript>] let Button label = Button [Text label] |>! OnClick (fun button _ -> button.Text <- "CLICKED") type ButtonControl(label: string) = inherit Web.Control() new () = new ButtonControl("unlabelled") [<JavaScript>] override this.Body = Button label :> _ module Site = let HomePage = View.Page "Home" [ Div [Text "Welcome to our website!"] ] |> Sitelet.Content "/" Home let AboutUsPage = View.Page "About Us" [ Div [Text "TODO: describe us."] Div [new Client.ButtonControl("Click me!")] ] |> Sitelet.Content "/about" AboutUs let Main = Sitelet.Sum [ HomePage AboutUsPage ] type Website() = interface IWebsite<Action> with member this.Actions = [] member this.Sitelet = Site.Main [<assembly: WebsiteAttribute(typeof<Website>)>] do ()